コード例 #1
0
ファイル: user.go プロジェクト: Pretlist/goread
func GetFeed(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	f := Feed{Url: r.FormValue("f")}
	var stars []string
	wg := sync.WaitGroup{}
	fk := gn.Key(&f)
	q := datastore.NewQuery(gn.Kind(&Story{})).Ancestor(fk).KeysOnly()
	q = q.Order("-" + IDX_COL)
	if cur := r.FormValue("c"); cur != "" {
		if dc, err := datastore.DecodeCursor(cur); err == nil {
			q = q.Start(dc)
		}
	} else {
		// grab the stars list on the first run
		wg.Add(1)
		go c.Step("stars", func(c mpg.Context) {
			gn := goon.FromContext(c)
			usk := starKey(c, f.Url, "")
			q := datastore.NewQuery(gn.Kind(&UserStar{})).Ancestor(gn.Key(usk).Parent()).KeysOnly()
			keys, _ := gn.GetAll(q, nil)
			stars = make([]string, len(keys))
			for i, key := range keys {
				stars[i] = starID(key)
			}
			wg.Done()
		})
	}
	iter := gn.Run(q)
	var stories []*Story
	for i := 0; i < 20; i++ {
		if k, err := iter.Next(nil); err == nil {
			stories = append(stories, &Story{
				Id:     k.StringID(),
				Parent: k.Parent(),
			})
		} else if err == datastore.Done {
			break
		} else {
			serveError(w, err)
			return
		}
	}
	cursor := ""
	if ic, err := iter.Cursor(); err == nil {
		cursor = ic.String()
	}
	gn.GetMulti(&stories)
	wg.Wait()
	b, _ := json.Marshal(struct {
		Cursor  string
		Stories []*Story
		Stars   []string `json:",omitempty"`
	}{
		Cursor:  cursor,
		Stories: stories,
		Stars:   stars,
	})
	w.Write(b)
}
コード例 #2
0
ファイル: tasks.go プロジェクト: Pretlist/goread
func CreateChannel(c mpg.Context, w http.ResponseWriter, r *http.Request) {

	cn := appengine.NewContext(r)
	urlfetchClient := urlfetch.Client(cn)

	client := pusher.Client{
		AppId:      "184465",
		Key:        "e2aac50ec511259792df",
		Secret:     "72f723c5a34c6d3efa0d",
		HttpClient: urlfetchClient,
	}

	gn := goon.FromContext(c)

	ch := Channel{Id: r.FormValue("id")}

	if err := gn.Get(&ch); err != nil {
		ch = Channel{Id: r.FormValue("id"), FeedLinks: r.FormValue("feedLinks"), DisplayName: r.FormValue("displayName"), Tags: r.FormValue("tags")}
		gn.Put(&ch)
		client.Trigger("test_channel", "create_channel", ch)
		return
	}

	if strings.Contains(ch.FeedLinks, r.FormValue("feedLinks")) {
		//fmt.Printf("Found subStr in str \n")
	} else {
		feedLinks := ch.FeedLinks + ";" + r.FormValue("feedLinks")
		ch.FeedLinks = feedLinks
		gn.Put(&ch)
	}
	client.Trigger("test_channel", "create_channel", ch)
}
コード例 #3
0
ファイル: user.go プロジェクト: Pretlist/goread
func MarkRead(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	read := make(Read)
	var stories []readStory
	defer r.Body.Close()
	b, _ := ioutil.ReadAll(r.Body)
	if err := json.Unmarshal(b, &stories); err != nil {
		serveError(w, err)
		return
	}
	gn.RunInTransaction(func(gn *goon.Goon) error {
		u := &User{Id: cu.ID}
		ud := &UserData{
			Id:     "data",
			Parent: gn.Key(u),
		}
		if err := gn.Get(ud); err != nil {
			return err
		}
		gob.NewDecoder(bytes.NewReader(ud.Read)).Decode(&read)
		for _, s := range stories {
			read[s] = true
		}
		var b bytes.Buffer
		gob.NewEncoder(&b).Encode(&read)
		ud.Read = b.Bytes()
		_, err := gn.Put(ud)
		return err
	}, nil)
}
コード例 #4
0
ファイル: user.go プロジェクト: Pretlist/goread
func MarkUnread(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	read := make(Read)
	f := r.FormValue("feed")
	s := r.FormValue("story")
	rs := readStory{Feed: f, Story: s}
	u := &User{Id: cu.ID}
	ud := &UserData{
		Id:     "data",
		Parent: gn.Key(u),
	}
	gn.RunInTransaction(func(gn *goon.Goon) error {
		if err := gn.Get(ud); err != nil {
			return err
		}
		gob.NewDecoder(bytes.NewReader(ud.Read)).Decode(&read)
		delete(read, rs)
		b := bytes.Buffer{}
		gob.NewEncoder(&b).Encode(&read)
		ud.Read = b.Bytes()
		_, err := gn.Put(ud)
		return err
	}, nil)
}
コード例 #5
0
ファイル: user.go プロジェクト: Pretlist/goread
func GetContents(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	var reqs []struct {
		Feed  string
		Story string
	}
	defer r.Body.Close()
	b, _ := ioutil.ReadAll(r.Body)
	if err := json.Unmarshal(b, &reqs); err != nil {
		serveError(w, err)
		return
	}
	scs := make([]*StoryContent, len(reqs))
	gn := goon.FromContext(c)
	for i, r := range reqs {
		f := &Feed{Url: r.Feed}
		s := &Story{Id: r.Story, Parent: gn.Key(f)}
		scs[i] = &StoryContent{Id: 1, Parent: gn.Key(s)}
	}
	gn.GetMulti(scs)
	ret := make([]string, len(reqs))
	for i, sc := range scs {
		ret[i] = sc.content()
	}
	b, _ = json.Marshal(&ret)
	w.Write(b)
}
コード例 #6
0
ファイル: user.go プロジェクト: Pretlist/goread
func AddSubscription(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	backupOPML(c)
	cu := user.Current(c)
	url := r.FormValue("url")
	o := &OpmlOutline{
		Outline: []*OpmlOutline{
			{XmlUrl: url},
		},
	}
	if err := addFeed(c, cu.ID, o); err != nil {
		c.Errorf("add sub error (%s): %s", url, err.Error())
		serveError(w, err)
		return
	}

	gn := goon.FromContext(c)
	ud := UserData{Id: "data", Parent: gn.Key(&User{Id: cu.ID})}
	gn.Get(&ud)
	if err := mergeUserOpml(c, &ud, o); err != nil {
		c.Errorf("add sub error opml (%v): %v", url, err)
		serveError(w, err)
		return
	}
	gn.PutMulti([]interface{}{&ud, &Log{
		Parent: ud.Parent,
		Id:     time.Now().UnixNano(),
		Text:   fmt.Sprintf("add sub: %v", url),
	}})
	if r.Method == "GET" {
		http.Redirect(w, r, routeUrl("main"), http.StatusFound)
	}
	backupOPML(c)
}
コード例 #7
0
ファイル: user.go プロジェクト: Pretlist/goread
func FeedHistory(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	uk := gn.Key(&u)
	if v := r.FormValue("v"); len(v) == 0 {
		q := datastore.NewQuery(gn.Kind(&UserOpml{})).Ancestor(uk).KeysOnly()
		keys, err := gn.GetAll(q, nil)
		if err != nil {
			serveError(w, err)
			return
		}
		times := make([]string, len(keys))
		for i, k := range keys {
			times[i] = strconv.FormatInt(k.IntID(), 10)
		}
		b, _ := json.Marshal(&times)
		w.Write(b)
	} else {
		a, _ := strconv.ParseInt(v, 10, 64)
		uo := UserOpml{Id: a, Parent: uk}
		if err := gn.Get(&uo); err != nil {
			serveError(w, err)
			return
		}
		downloadOpml(w, uo.opml(), cu.Email)
	}
}
コード例 #8
0
ファイル: tasks.go プロジェクト: Pretlist/goread
func UpdateFeed(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(appengine.Timeout(c, time.Minute))
	url := r.FormValue("feed")
	if url == "" {
		c.Errorf("empty update feed")
		return
	}
	c.Debugf("update feed %s", url)
	last := len(r.FormValue("last")) > 0
	f := Feed{Url: url}
	s := ""
	defer func() {
		gn.Put(&Log{
			Parent: gn.Key(&f),
			Id:     time.Now().UnixNano(),
			Text:   "UpdateFeed - " + s,
		})
	}()
	if err := gn.Get(&f); err == datastore.ErrNoSuchEntity {
		c.Errorf("no such entity - " + url)
		s += "NSE"
		return
	} else if err != nil {
		s += "err - " + err.Error()
		return
	} else if last {
		// noop
	} else if time.Now().Before(f.NextUpdate) {
		c.Errorf("feed %v already updated: %v", url, f.NextUpdate)
		s += "already updated"
		return
	}

	feedError := func(err error) {
		s += "feed err - " + err.Error()
		f.Errors++
		v := f.Errors + 1
		const max = 24 * 7
		if v > max {
			v = max
		} else if f.Errors == 1 {
			v = 0
		}
		f.NextUpdate = time.Now().Add(time.Hour * time.Duration(v))
		gn.Put(&f)
		c.Warningf("error with %v (%v), bump next update to %v, %v", url, f.Errors, f.NextUpdate, err)
	}

	if feed, stories, err := fetchFeed(c, f.Url, f.Url); err == nil {
		if err := updateFeed(c, f.Url, feed, stories, false, false, last); err != nil {
			feedError(err)
		} else {
			s += "success"
		}
	} else {
		feedError(err)
	}
	f.Subscribe(c)
}
コード例 #9
0
ファイル: admin.go プロジェクト: biggtfish/goread
func AdminStats(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	uc, _ := datastore.NewQuery(gn.Kind(&User{})).Count(c)
	templates.ExecuteTemplate(w, "admin-stats.html", struct {
		Users int
	}{
		uc,
	})
}
コード例 #10
0
ファイル: types.go プロジェクト: biggtfish/goread
func starKey(c appengine.Context, feed, story string) *UserStar {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	uk := gn.Key(&u)
	return &UserStar{
		Parent: datastore.NewKey(c, "USF", feed, 0, uk),
		Id:     story,
	}
}
コード例 #11
0
ファイル: dev.go プロジェクト: biggtfish/goread
func ClearFeeds(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	if !isDevServer {
		return
	}

	cu := user.Current(c)
	gn := goon.FromContext(c)
	done := make(chan bool)
	go func() {
		u := &User{Id: cu.ID}
		defer func() { done <- true }()
		ud := &UserData{Id: "data", Parent: gn.Key(u)}
		if err := gn.Get(u); err != nil {
			c.Errorf("user del err: %v", err.Error())
			return
		}
		gn.Get(ud)
		u.Read = time.Time{}
		ud.Read = nil
		ud.Opml = nil
		gn.PutMulti([]interface{}{u, ud})
		c.Infof("%v cleared", u.Email)
	}()
	del := func(kind string) {
		defer func() { done <- true }()
		q := datastore.NewQuery(kind).KeysOnly()
		keys, err := gn.GetAll(q, nil)
		if err != nil {
			c.Errorf("err: %v", err.Error())
			return
		}
		if err := gn.DeleteMulti(keys); err != nil {
			c.Errorf("err: %v", err.Error())
			return
		}
		c.Infof("%v deleted", kind)
	}
	types := []interface{}{
		&Feed{},
		&Story{},
		&StoryContent{},
		&Log{},
		&UserOpml{},
	}
	for _, i := range types {
		k := gn.Kind(i)
		go del(k)
	}

	for i := 0; i < len(types); i++ {
		<-done
	}

	http.Redirect(w, r, fmt.Sprintf("%s?url=http://localhost:8080%s", routeUrl("add-subscription"), routeUrl("test-atom")), http.StatusFound)
}
コード例 #12
0
ファイル: admin.go プロジェクト: biggtfish/goread
func AdminSubHub(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	f := Feed{Url: r.FormValue("f")}
	if err := gn.Get(&f); err != nil {
		serveError(w, err)
		return
	}
	f.Subscribed = time.Time{}
	f.Subscribe(c)
	fmt.Fprintf(w, "subscribed")
}
コード例 #13
0
ファイル: user.go プロジェクト: Pretlist/goread
func SetStatus(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	status := r.FormValue("status")
	readChats := r.FormValue("readChats")
	gn := goon.FromContext(c)
	q := datastore.NewQuery(gn.Kind(&User{}))
	var users []User

	_, err1 := gn.GetAll(q, &users)

	if err1 != nil {
		http.Error(w, err1.Error(), http.StatusInternalServerError)
		return
	}

	for i := 0; i < len(users); i++ {
		if strings.ToLower(users[i].Email) == strings.ToLower(cu.Email) {
			users[i].Status = status
			gn.Put(&users[i])
		}
	}

	if status == "f" {
		q = datastore.NewQuery(gn.Kind(&Chat{}))

		var chats []Chat

		_, err2 := gn.GetAll(q, &chats)
		if err2 != nil {
			return
		}

		lastChat := chats[len(chats)-1]

		cc := ChatCursor{
			Id:        cu.Email,
			Cursor:    lastChat.Id,
			ReadChats: readChats,
		}
		gn.Put(&cc)
	}

	cn := appengine.NewContext(r)
	urlfetchClient := urlfetch.Client(cn)

	client := pusher.Client{
		AppId:      "184465",
		Key:        "e2aac50ec511259792df",
		Secret:     "72f723c5a34c6d3efa0d",
		HttpClient: urlfetchClient,
	}

	client.Trigger("test_channel", "user_status_changed", "")
}
コード例 #14
0
ファイル: tasks.go プロジェクト: Pretlist/goread
func UpdateFeedLast(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	url := r.FormValue("feed")
	c.Debugf("update feed last %s", url)
	f := Feed{Url: url}
	if err := gn.Get(&f); err != nil {
		return
	}
	f.LastViewed = time.Now()
	gn.Put(&f)
}
コード例 #15
0
ファイル: tasks.go プロジェクト: Pretlist/goread
// Task used to subscribe a feed to push.
func SubscribeFeed(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	start := time.Now()
	gn := goon.FromContext(c)
	f := Feed{Url: r.FormValue("feed")}
	fk := gn.Key(&f)
	s := ""
	defer func() {
		gn.Put(&Log{
			Parent: fk,
			Id:     time.Now().UnixNano(),
			Text:   "SubscribeFeed - start " + start.String() + " - f.sub " + f.Subscribed.String() + " - " + s,
		})
	}()
	if err := gn.Get(&f); err != nil {
		c.Errorf("%v: %v", err, f.Url)
		serveError(w, err)
		s += "err"
		return
	} else if f.IsSubscribed() {
		s += "is subscribed"
		return
	}
	u := url.Values{}
	u.Add("hub.callback", f.PubSubURL())
	u.Add("hub.mode", "subscribe")
	u.Add("hub.verify", "sync")
	fu, _ := url.Parse(f.Url)
	fu.Fragment = ""
	u.Add("hub.topic", fu.String())
	req, err := http.NewRequest("POST", f.Hub, strings.NewReader(u.Encode()))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	cl := &http.Client{
		Transport: &urlfetch.Transport{
			Context:  c,
			Deadline: time.Minute,
		},
	}
	resp, err := cl.Do(req)
	if err != nil {
		c.Errorf("req error: %v", err)
	} else if resp.StatusCode != http.StatusNoContent {
		f.Subscribed = time.Now().Add(time.Hour * 48)
		gn.Put(&f)
		if resp.StatusCode != http.StatusConflict {
			c.Errorf("resp: %v - %v", f.Url, resp.Status)
			c.Errorf("%s", resp.Body)
		}
		s += "resp err"
	} else {
		c.Infof("subscribed: %v", f.Url)
		s += "success"
	}
}
コード例 #16
0
ファイル: user.go プロジェクト: nikmahes/goread
func LoginGoogle(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	if cu := user.Current(c); cu != nil {
		gn := goon.FromContext(c)
		u := &User{Id: cu.ID}
		if err := gn.Get(u); err == datastore.ErrNoSuchEntity {
			u.Email = cu.Email
			u.Read = time.Now().Add(-time.Hour * 24)
			gn.Put(u)
		}
	}

	http.Redirect(w, r, routeUrl("main"), http.StatusFound)
}
コード例 #17
0
ファイル: api.go プロジェクト: Pretlist/goread
func CreateMessage(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)

	msg := Message{
		Title:       r.FormValue("title"),
		CreatedBy:   r.FormValue("createdBy"),
		DateCreated: r.FormValue("dateCreated"),
		Channel:     r.FormValue("channel"),
		DocId:       r.FormValue("docId"),
		Content:     r.FormValue("content"),
	}
	gn.Put(&msg)
}
コード例 #18
0
ファイル: admin.go プロジェクト: biggtfish/goread
func AllFeedsOpml(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	q := datastore.NewQuery(gn.Kind(&Feed{})).KeysOnly()
	keys, _ := gn.GetAll(q, nil)
	fs := make([]*Feed, len(keys))
	for i, k := range keys {
		fs[i] = &Feed{Url: k.StringID()}
	}
	b := feedsToOpml(fs)
	w.Header().Add("Content-Type", "text/xml")
	w.Header().Add("Content-Disposition", "attachment; filename=all.opml")
	w.Write(b)
}
コード例 #19
0
ファイル: utils.go プロジェクト: Pretlist/goread
func includes(c mpg.Context, w http.ResponseWriter, r *http.Request) *Includes {
	i := &Includes{
		Angular:             Angular,
		BootstrapCss:        BootstrapCss,
		BootstrapJs:         BootstrapJs,
		FontAwesome:         FontAwesome,
		Jquery:              Jquery,
		JqueryUI:            JqueryUI,
		Underscore:          Underscore,
		MiniProfiler:        c.Includes(),
		GoogleAnalyticsId:   GOOGLE_ANALYTICS_ID,
		GoogleAnalyticsHost: GOOGLE_ANALYTICS_HOST,
		SubURL:              subURL,
		IsDev:               isDevServer,
		/*		StripeKey:           STRIPE_KEY,
				StripePlans:         STRIPE_PLANS,*/
	}

	session, _ := Store.Get(r, "pretlist-session")
	i.Session = session

	if cu := user.Current(c); cu != nil {
		gn := goon.FromContext(c)
		user := &User{Id: cu.ID}
		if err := gn.Get(user); err == nil {
			i.User = user
			i.IsAdmin = cu.Admin

			if len(user.Messages) > 0 {
				i.Messages = user.Messages
				user.Messages = nil
				gn.Put(user)
			}

			/*
				if _, err := r.Cookie("update-bug"); err != nil {
					i.Messages = append(i.Messages, "Go Read had some problems updating feeds. It may take a while for new stories to appear again. Sorry about that.")
					http.SetCookie(w, &http.Cookie{
						Name: "update-bug",
						Value: "done",
						Expires: time.Now().Add(time.Hour * 24 * 7),
					})
				}
			*/
		}
	}

	return i
}
コード例 #20
0
ファイル: charge.go プロジェクト: biggtfish/goread
func Charge(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	uc := &UserCharge{Id: 1, Parent: gn.Key(&u)}
	if err := gn.Get(&u); err != nil {
		serveError(w, err)
		return
	} else if u.Account != AFree {
		serveError(w, fmt.Errorf("You're already subscribed."))
		return
	}
	if err := gn.Get(uc); err == nil && len(uc.Customer) > 0 {
		serveError(w, fmt.Errorf("You're already subscribed."))
		return
	} else if err != datastore.ErrNoSuchEntity {
		serveError(w, err)
		return
	}
	resp, err := stripe(c, "POST", "customers", url.Values{
		"email":       {u.Email},
		"description": {u.Id},
		"card":        {r.FormValue("token")},
		"plan":        {r.FormValue("plan")},
	}.Encode())
	if err != nil {
		serveError(w, err)
		return
	} else if resp.StatusCode != http.StatusOK {
		var se StripeError
		defer resp.Body.Close()
		b, _ := ioutil.ReadAll(resp.Body)
		if err := json.Unmarshal(b, &se); err == nil {
			serveError(w, fmt.Errorf(se.Error.Message))
		} else {
			serveError(w, fmt.Errorf("Error"))
		}
		c.Errorf("status: %v, %s", resp.StatusCode, b)
		return
	}
	uc, err = setCharge(c, resp)
	if err != nil {
		serveError(w, err)
		return
	}
	b, _ := json.Marshal(&uc)
	w.Write(b)
}
コード例 #21
0
ファイル: api.go プロジェクト: Pretlist/goread
func GetMessages(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	q := datastore.NewQuery(gn.Kind(&Message{}))
	var msgs []Message
	_, err1 := gn.GetAll(q, &msgs)
	if err1 != nil {
		return
	}
	b, err2 := json.Marshal(msgs)
	if err2 != nil {
		return
	}

	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Write(b)
}
コード例 #22
0
ファイル: admin.go プロジェクト: biggtfish/goread
func AdminFeed(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	f := Feed{Url: r.FormValue("f")}
	if err := gn.Get(&f); err != nil {
		serveError(w, err)
		return
	}
	q := datastore.NewQuery(gn.Kind(&Story{})).KeysOnly()
	fk := gn.Key(&f)
	q = q.Ancestor(fk)
	q = q.Limit(100)
	q = q.Order("-" + IDX_COL)
	keys, _ := gn.GetAll(q, nil)
	stories := make([]*Story, len(keys))
	for j, key := range keys {
		stories[j] = &Story{
			Id:     key.StringID(),
			Parent: fk,
		}
	}
	gn.GetMulti(stories)
	lk := gn.Key(&Log{Parent: fk, Id: time.Now().Add(-time.Hour * 6).UnixNano()})
	q = datastore.NewQuery(lk.Kind()).KeysOnly()
	q = q.Ancestor(fk)
	q = q.Filter("__key__ >", lk)
	keys, _ = gn.GetAll(q, nil)
	logs := make([]*Log, len(keys))
	for j, key := range keys {
		logs[j] = &Log{
			Id:     key.IntID(),
			Parent: fk,
		}
	}
	gn.GetMulti(logs)

	templates.ExecuteTemplate(w, "admin-feed.html", struct {
		Feed    *Feed
		Logs    []*Log
		Stories []*Story
		Now     time.Time
	}{
		&f,
		logs,
		stories,
		time.Now(),
	})
}
コード例 #23
0
ファイル: admin.go プロジェクト: biggtfish/goread
func AdminUser(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	q := datastore.NewQuery(gn.Kind(&User{})).Limit(1)
	q = q.Filter("e =", r.FormValue("u"))
	it := gn.Run(q)
	var u User
	ud := UserData{Id: "data"}
	var h []Log
	k, err := it.Next(&u)
	if err != nil {
		serveError(w, err)
		return
	}
	ud.Parent = gn.Key(&u)
	gn.Get(&ud)
	until := r.FormValue("until")
	if d, err := time.Parse("2006-01-02", until); err == nil {
		u.Until = d
		gn.Put(&u)
	}
	if o := []byte(r.FormValue("opml")); len(o) > 0 {
		opml := Opml{}
		if err := json.Unmarshal(o, &opml); err != nil {
			serveError(w, err)
			return
		}
		ud.Opml = o
		if _, err := gn.Put(&ud); err != nil {
			serveError(w, err)
			return
		}
		c.Infof("opml updated")
	}
	q = datastore.NewQuery(gn.Kind(&Log{})).Ancestor(k)
	_, err = gn.GetAll(q, &h)
	if err := templates.ExecuteTemplate(w, "admin-user.html", struct {
		User User
		Data UserData
		Log  []Log
	}{
		u,
		ud,
		h,
	}); err != nil {
		serveError(w, err)
	}
}
コード例 #24
0
ファイル: main.go プロジェクト: biggtfish/goread
func addFeed(c mpg.Context, userid string, outline *OpmlOutline) error {
	gn := goon.FromContext(c)
	o := outline.Outline[0]
	c.Infof("adding feed %v to user %s", o.XmlUrl, userid)
	fu, ferr := url.Parse(o.XmlUrl)
	if ferr != nil {
		return ferr
	}
	fu.Fragment = ""
	o.XmlUrl = fu.String()

	f := Feed{Url: o.XmlUrl}
	if err := gn.Get(&f); err == datastore.ErrNoSuchEntity {
		if feed, stories, err := fetchFeed(c, o.XmlUrl, o.XmlUrl); err != nil {
			return fmt.Errorf("could not add feed %s: %v", o.XmlUrl, err)
		} else {
			f = *feed
			f.Updated = time.Time{}
			f.Checked = f.Updated
			f.NextUpdate = f.Updated
			f.LastViewed = time.Now()
			gn.Put(&f)
			for _, s := range stories {
				s.Created = s.Published
			}
			if err := updateFeed(c, f.Url, feed, stories, false, false, false); err != nil {
				return err
			}

			o.XmlUrl = feed.Url
			o.HtmlUrl = feed.Link
			if o.Title == "" {
				o.Title = feed.Title
			}
		}
	} else if err != nil {
		return err
	} else {
		o.HtmlUrl = f.Link
		if o.Title == "" {
			o.Title = f.Title
		}
	}
	o.Text = ""

	return nil
}
コード例 #25
0
ファイル: tasks.go プロジェクト: Pretlist/goread
func GetChannels(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	q := datastore.NewQuery(gn.Kind(&Channel{}))
	var ch []Channel

	_, err1 := gn.GetAll(q, &ch)
	if err1 != nil {
		return
	}

	b, err2 := json.Marshal(ch)
	if err2 != nil {
		return
	}

	w.Write(b)
}
コード例 #26
0
ファイル: tasks.go プロジェクト: Pretlist/goread
func SubscribeCallback(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	furl := r.FormValue("feed")
	b, _ := base64.URLEncoding.DecodeString(furl)
	f := Feed{Url: string(b)}
	c.Infof("url: %v", f.Url)
	if err := gn.Get(&f); err != nil {
		http.Error(w, "", http.StatusNotFound)
		return
	}
	if r.Method == "GET" {
		if f.NotViewed() || r.FormValue("hub.mode") != "subscribe" || r.FormValue("hub.topic") != f.Url {
			http.Error(w, "", http.StatusNotFound)
			return
		}
		w.Write([]byte(r.FormValue("hub.challenge")))
		i, _ := strconv.Atoi(r.FormValue("hub.lease_seconds"))
		f.Subscribed = time.Now().Add(time.Second * time.Duration(i))
		gn.PutMulti([]interface{}{&f, &Log{
			Parent: gn.Key(&f),
			Id:     time.Now().UnixNano(),
			Text:   "SubscribeCallback - subscribed - " + f.Subscribed.String(),
		}})
		c.Debugf("subscribed: %v - %v", f.Url, f.Subscribed)
		return
	} else if !f.NotViewed() {
		c.Infof("push: %v", f.Url)
		gn.Put(&Log{
			Parent: gn.Key(&f),
			Id:     time.Now().UnixNano(),
			Text:   "SubscribeCallback - push update",
		})
		defer r.Body.Close()
		b, _ := ioutil.ReadAll(r.Body)
		nf, ss, err := ParseFeed(c, r.Header.Get("Content-Type"), f.Url, f.Url, b)
		if err != nil {
			c.Errorf("parse error: %v", err)
			return
		}
		if err := updateFeed(c, f.Url, nf, ss, false, true, false); err != nil {
			c.Errorf("push error: %v", err)
		}
	} else {
		c.Infof("not viewed")
	}
}
コード例 #27
0
ファイル: user.go プロジェクト: Pretlist/goread
func ExportOpml(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	var u User
	if uid := r.FormValue("u"); len(uid) != 0 && user.IsAdmin(c) {
		u = User{Id: uid}
	} else {
		cu := user.Current(c)
		u = User{Id: cu.ID}
	}
	ud := UserData{Id: "data", Parent: gn.Key(&u)}
	if err := gn.Get(&u); err != nil {
		serveError(w, err)
		return
	}
	gn.Get(&ud)
	downloadOpml(w, ud.Opml, u.Email)
}
コード例 #28
0
ファイル: api.go プロジェクト: Pretlist/goread
func UsersList(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	gn := goon.FromContext(c)
	q := datastore.NewQuery(gn.Kind(&User{}))
	var us []User

	_, err1 := gn.GetAll(q, &us)
	if err1 != nil {
		return
	}

	b, err2 := json.Marshal(us)
	if err2 != nil {
		return
	}

	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Write(b)
}
コード例 #29
0
ファイル: types.go プロジェクト: biggtfish/goread
func (f *Feed) Subscribe(c appengine.Context) {
	if !f.IsSubscribed() {
		gn := goon.FromContext(c)
		gn.Put(&Log{
			Parent: gn.Key(&f),
			Id:     time.Now().UnixNano(),
			Text:   fmt.Sprintf("Subscribe %v", f.Subscribed.String()),
		})
		t := taskqueue.NewPOSTTask(routeUrl("subscribe-feed"), url.Values{
			"feed": {f.Url},
		})
		if _, err := taskqueue.Add(c, t, "update-manual"); err != nil {
			c.Errorf("taskqueue error: %v", err.Error())
		} else {
			c.Warningf("subscribe feed: %v", f.Url)
		}
	}
}
コード例 #30
0
ファイル: user.go プロジェクト: Pretlist/goread
func SaveOptions(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	gn.RunInTransaction(func(gn *goon.Goon) error {
		u := User{Id: cu.ID}
		if err := gn.Get(&u); err != nil {
			serveError(w, err)
			return nil
		}
		u.Options = r.FormValue("options")
		_, err := gn.PutMulti([]interface{}{&u, &Log{
			Parent: gn.Key(&u),
			Id:     time.Now().UnixNano(),
			Text:   fmt.Sprintf("save options: %v", len(u.Options)),
		}})
		return err
	}, nil)
}