예제 #1
0
func init() {
	recordFormValidator.Field("start_at").Func(util.ValidateDateTimeString)
	recordFormValidator.Field("end_at").Func(util.ValidateDateTimeString)

	app.Api.Get("/records/",
		func(res *wcg.Response, req *wcg.Request) {
			ctx := gae.NewContext(req)
			d := NewRecordCacheDriver(app.Key, ctx, req.Logger)
			if list, err := d.GetRecords(req.Query("force") == "1"); err != nil {
				app.Api.InternalError(res, req, err)
			} else {
				res.WriteJson(list)
			}
		},
	)
	app.Api.Post("/records/", lib.Family.Required(
		func(res *wcg.Response, req *wcg.Request) {
			if err := recordFormValidator.Eval(req.HttpRequest().PostForm); err != nil {
				app.Api.BadRequest(res, req, err)
				return
			}

			ctx := gae.NewContext(req)
			d := NewRecordCacheDriver(app.Key, ctx, req.Logger)
			start, _ := util.ParseDateTime(req.Form("start_at"))
			end, _ := util.ParseDateTime(req.Form("end_at"))
			rec := tv.NewTvRecord(
				req.Form("title"), req.Form("category"),
				start, end,
				req.Form("cid"), req.Form("sid"),
				req.User.Id(),
			)

			if err := d.Save(rec); err != nil {
				app.Api.InternalError(res, req, err)
			} else {
				app.Api.Created(res, req, fmt.Sprintf("/records/%s.json", rec.Key()))
			}
		},
	))

	app.Api.Delete("/records/:key.json", lib.Family.Required(
		func(res *wcg.Response, req *wcg.Request) {
			d := NewRecordCacheDriver(app.Key, gae.NewContext(req), req.Logger)
			if err := d.Delete(req.Param("key")); err != nil {
				app.Api.InternalError(res, req, err)
				return
			} else {
				app.Api.Ok(res, req)
			}
		},
	))
}
예제 #2
0
파일: context.go 프로젝트: speedland/apps
func NewAppContextFromRequest(req *wcg.Request) *AppContext {
	return &AppContext{
		GetCurrentApp(req),
		gae.NewContext(req),
		req.Logger,
	}
}
예제 #3
0
파일: blogs.go 프로젝트: speedland/rakugaki
func fetchBlog(res *wcg.Response, req *wcg.Request, includePosts bool) (*models.Blog, *supports.Page, error) {
	// default query for posts.
	id := req.Param("blog_id")
	driver := models.NewBlogDriver(gae.NewContext(req), req.Logger)
	blog, query, err := driver.PostQuery(id)
	if err != nil {
		if err == models.ErrBlogNotFound {
			res.WriteHeader(404)
			res.WriteString("Not found")
			res.End()
			return nil, nil, err
		}
		res.RenderInternalError(err.Error())
		return nil, nil, err
	}

	if !includePosts {
		return blog, supports.EmptyPage, nil
	}
	query = query.Filter("IsNew =", false).Filter("IsDraft =", false).Order("-PostDate").Order("-UpdatedAt")
	per_page := wcg.ParseInt(req.Query("num"), AppConfig.DefaultPostsFetched, 0, AppConfig.MaxPostsFetched)
	current := wcg.ParseInt(req.Query("p"), 0, 0, wcg.ParseIntMax)
	page, err := supports.NewPage(current, per_page, query)
	if err != nil {
		res.RenderInternalError("Post pagination error: %v", err)
		return nil, nil, err
	}
	return blog, page, nil
}
예제 #4
0
파일: posts.go 프로젝트: speedland/rakugaki
func fetchPostForUpdate(req *wcg.Request, res *wcg.Response, blog *models.Blog) (*models.Post, error) {
	driver := models.NewPostDriver(gae.NewContext(req), req.Logger)
	id := req.Param("post_id")
	blogId := req.Param("blog_id")
	post, err := driver.FindPostById(id, blogId)
	if err != nil {
		if err == models.ErrPostNotFound {
			res.WriteHeader(404)
			res.WriteString("Not found")
			res.End()
			return nil, err
		}
		res.RenderInternalError(err.Error())
		return nil, err
	}
	if blog.Id != post.BlogId {
		res.WriteHeader(403)
		res.WriteString("You could not manage that blog.")
		res.End()
	}

	if post.OwnerId != req.User.Id() {
		res.WriteHeader(403)
		res.WriteString("You could not manage this post.")
		res.End()
		return nil, err
	}
	return post, err
}
예제 #5
0
파일: posts.go 프로젝트: speedland/rakugaki
func fetchPost(res *wcg.Response, req *wcg.Request, blog *models.Blog) (*models.Post, error) {
	driver := models.NewPostDriver(gae.NewContext(req), req.Logger)
	id := req.Param("post_id")
	blogId := req.Param("blog_id")
	post, err := driver.FindPostById(id, blogId)
	if err != nil {
		if err == models.ErrPostNotFound {
			res.WriteHeader(404)
			res.WriteString("Not found")
			res.End()
			return nil, err
		}
		res.RenderInternalError(err.Error())
		return nil, err
	}
	if post.PostState() != models.PostStatePublished {
		if post.OwnerId != req.User.Id() {
			res.WriteHeader(404)
			res.WriteString("Not found")
			res.End()
			return nil, err
		}
	}
	return post, err
}
예제 #6
0
func getVersion(res *wcg.Response, req *wcg.Request) {
	stats, _ := runtime.Stats(gae.NewContext(req))
	res.WriteJson(map[string]interface{}{
		"version":   lib.APP_COMMIT,
		"timestamp": lib.APP_TIMESTAMP,
		"stats":     stats,
	})
}
예제 #7
0
파일: posts.go 프로젝트: speedland/rakugaki
func createPostHandler(res *wcg.Response, req *wcg.Request) {
	blog, _, err := fetchBlogForUpdate(res, req, false)
	if err != nil {
		return
	}
	post := models.NewPost(req.User.Id(), blog.Id)
	err = models.NewPostDriver(gae.NewContext(req), req.Logger).SavePost(post)
	if err != nil {
		res.RenderInternalError(err.Error())
		return
	}
	res.Redirect(fmt.Sprintf("/admin/blogs/%s/%s/", blog.Id, post.Id), http.StatusSeeOther)
}
예제 #8
0
func init() {
	app.Api.Get("/channels/",
		func(res *wcg.Response, req *wcg.Request) {
			if list, err := listTvChannels(res, req); err != nil {
				app.Api.InternalError(res, req, err)
			} else {
				res.WriteJson(list)
			}
		},
	)
	app.Api.Post("/channels/", lib.Admin.Required(
		func(res *wcg.Response, req *wcg.Request) {
			ctx := gae.NewContext(req)
			d := NewTvChannelDriver(app.Key, ctx, req.Logger)
			mc := memcache.NewDriver(ctx, req.Logger)
			if err := d.AddChannel(req.Form("cid"), req.Form("sid"), req.Form("name"), req.Form("iepg_station_id")); err != nil {
				lib.InternalError(res, req, err)
			} else {
				mc.Delete(MC_KEY_CHANNELS)
				id := fmt.Sprintf("%s/%s", req.Form("cid"), req.Form("sid"))
				app.Api.Created(res, req, id)
			}
		},
	))
	app.Api.Delete("/channels/:cid/:sid.json", lib.Admin.Required(
		func(res *wcg.Response, req *wcg.Request) {
			ctx := gae.NewContext(req)
			d := NewTvChannelDriver(app.Key, ctx, req.Logger)
			mc := memcache.NewDriver(ctx, req.Logger)
			if err := d.DelChannel(req.Param("cid"), req.Param("sid")); err != nil {
				lib.InternalError(res, req, err)
			} else {
				mc.Delete(MC_KEY_CHANNELS)
				app.Api.Ok(res, req)
			}
		},
	))
}
예제 #9
0
파일: blogs.go 프로젝트: speedland/rakugaki
func deleteBlogHandler(res *wcg.Response, req *wcg.Request) {
	driver := models.NewBlogDriver(gae.NewContext(req), req.Logger)
	err := driver.DeleteBlog(req.Param("blog_id"), req.User.Id())
	if err != nil {
		if supports.IsValidationError(err) {
			res.WriteJsonWithStatus(400, nil, err)
		} else if err == models.ErrBlogNotOwned {
			res.WriteJsonWithStatus(403, nil, no_permission)
		} else if err == models.ErrBlogNotFound {
			res.WriteJsonWithStatus(404, nil, not_found)
		} else {
			res.RenderInternalError(err.Error())
		}
		return
	}
	res.WriteJsonWithStatus(200, nil, ok)
}
예제 #10
0
파일: top.go 프로젝트: speedland/rakugaki
func TopHandler(res *Response, req *Request) {
	if !IsGuest(req.User) {
		driver := models.NewBlogDriver(gae.NewContext(req), req.Logger)
		blogs, err := driver.FindBlogsByOwner(req.User.Id())
		if err != nil {
			res.RenderInternalError(err.Error())
			return
		}
		if len(blogs) != 0 {
			res.SetLocal("blogs", blogs)
		} else {
			res.SetLocal("no_blogs", true)
		}
	}
	res.SetLocal("js", "/static/js/index.js")
	res.Templates("index.html", "header.html", "footer.html")
}
예제 #11
0
파일: posts.go 프로젝트: speedland/rakugaki
func deletePostHandler(res *wcg.Response, req *wcg.Request) {
	blog, _, err := fetchBlogForUpdate(res, req, false)
	if err != nil {
		return
	}
	post, err := fetchPostForUpdate(req, res, blog)
	if err != nil {
		return
	}
	err = models.NewPostDriver(gae.NewContext(req), req.Logger).DeletePost(post)
	if err != nil {
		if supports.IsValidationError(err) {
			res.WriteJsonWithStatus(400, nil, err)
		} else {
			res.RenderInternalError(err.Error())
		}
		return
	}
	res.WriteJsonWithStatus(200, nil, ok)
}
예제 #12
0
파일: posts.go 프로젝트: speedland/rakugaki
func updatePostHandler(res *wcg.Response, req *wcg.Request) {
	blog, _, err := fetchBlogForUpdate(res, req, false)
	if err != nil {
		return
	}
	post, err := fetchPostForUpdate(req, res, blog)
	if err != nil {
		return
	}
	post.Title = req.Form("title")
	post.Content = req.Form("content")
	post.IsDraft = req.Form("is_draft") == "true"
	post.IsNew = false
	post.PostDate, err = time.Parse(wcg.FormDateFormat, req.Form("post_date"))
	post.Tags = strings.Split(req.Form("tags"), ",")
	for i, v := range post.Tags {
		post.Tags[i] = strings.TrimSpace(v)
	}

	if err != nil {
		res.WriteHeader(400)
		res.WriteString("Invalid date format.")
		res.End()
	}
	driver := models.NewPostDriver(gae.NewContext(req), req.Logger)
	if AppConfig.GithubMarkdown {
		driver.HttpClient = gae.NewHttpClient(req)
	}
	err = driver.SavePost(post)
	if err != nil {
		if supports.IsValidationError(err) {
			res.WriteJsonWithStatus(400, nil, err)
		} else {
			res.RenderInternalError(err.Error())
		}
		return
	}

	req.Logger.Info("A post is created at %s.", post.Id)
	res.WriteJsonWithStatus(200, nil, ok)
}
예제 #13
0
파일: blogs.go 프로젝트: speedland/rakugaki
func createBlogHandler(res *wcg.Response, req *wcg.Request) {
	driver := models.NewBlogDriver(gae.NewContext(req), req.Logger)
	blog, err := driver.CreateBlog(
		req.Form("path"),
		req.Form("title"),
		req.Form("description"),
		req.User.Id(),
	)
	if err != nil {
		if err == models.ErrBlogAlreadyExists {
			res.WriteJsonWithStatus(409, nil, already_taken)
		} else if supports.IsValidationError(err) {
			res.WriteJsonWithStatus(400, nil, err)
		} else {
			res.RenderInternalError(err.Error())
		}
		return
	}
	res.WriteJsonWithStatus(201, map[string]string{
		"location": wcg.AbsoluteUrl(req, "/"+blog.Id),
	}, ok)
}
예제 #14
0
func listTvChannels(res *wcg.Response, req *wcg.Request) ([]*tv.TvChannel, error) {
	var list []*tv.TvChannel
	app := lib.GetCurrentApp(req)
	ctx := gae.NewContext(req)
	d := NewTvChannelDriver(app.Key, ctx, req.Logger)
	mc := memcache.NewDriver(ctx, req.Logger)
	err := mc.CachedObject(MC_KEY_CHANNELS, &list, func() (interface{}, error) {
		return d.AllAsList()
	}, req.Query("force") == "1")
	if err != nil {
		return nil, err
	} else {
		if len(list) == 0 {
			req.Logger.Warn("No channel is defined. Reset the configuraiton.")
			d.AddChannelList(defaultChannels)
			mc.Delete(MC_KEY_CHANNELS)
			mc.Set(MC_KEY_CHANNELS, defaultChannels)
			res.WriteJson(defaultChannels)
			return defaultChannels, nil
		} else {
			return list, nil
		}
	}
}
예제 #15
0
파일: blogs.go 프로젝트: speedland/rakugaki
func myblogRedirector(public bool) func(res *wcg.Response, req *wcg.Request) {
	return func(res *wcg.Response, req *wcg.Request) {
		if wcg.IsGuest(req.User) {
			res.Redirect("/", http.StatusSeeOther)
		} else {
			driver := models.NewBlogDriver(gae.NewContext(req), req.Logger)
			blogs, err := driver.FindBlogsByOwner(req.User.Id())
			if err != nil {
				res.RenderInternalError(err.Error())
				return
			}
			if len(blogs) > 0 {
				blog := blogs[0]
				if public {
					res.Redirect(fmt.Sprintf("/%s/", blog.Id), http.StatusSeeOther)
				} else {
					res.Redirect(fmt.Sprintf("/admin/blogs/%s/", blog.Id), http.StatusSeeOther)
				}
			} else {
				res.Redirect("/", http.StatusSeeOther)
			}
		}
	}
}
예제 #16
0
func init() {
	app.Cron.Get(
		"Crawl keyword IEPGs",
		"every 3 hours",
		"/keywords/crawl/",
		lib.Admin.Required(
			func(res *wcg.Response, req *wcg.Request) {
				var channels []*tv.TvChannel
				var cfglist []*tv.CrawlerConfig
				ctx := gae.NewContext(req)
				d := NewCrawlerConfigDriver(app.Key, ctx, req.Logger)
				mc := memcache.NewDriver(ctx, req.Logger)
				err := mc.CachedObject(MC_KEY_CHANNELS, &channels, func() (interface{}, error) {
					return NewTvChannelDriver(app.Key, ctx, req.Logger).AllAsList()
				}, false)
				if err != nil {
					app.Api.InternalError(res, req, err)
					return
				}

				req.Logger.Info("Retrieving all cralwer configurations...")
				q := d.NewQuery()
				q.Order("-CreatedAt")
				if _, err := q.GetAll(&cfglist); err != nil {
					app.Api.InternalError(res, req, err)
					return
				} else if len(cfglist) == 0 {
					req.Logger.Info("No cralwer configuration is found.")
					res.WriteJson(map[string]int{
						"updates": 0,
					})
					return
				} else {
					req.Logger.Info("Found %d configs, start crawling", len(cfglist))
					iepglist := make([]*tv.IEpg, 0)
					for i := range cfglist {
						if list, err := getIEpgListFromCrawlerConfig(res, req, cfglist[i], channels); err != nil {
							req.Logger.Warn("Failed to crawl %v: %v", cfglist[i], err)
						} else {
							iepglist = append(iepglist, list...)
						}
					}

					// TODO: Sync bulk update
					d := NewRecordCacheDriver(app.Key, ctx, req.Logger)
					if keys, err := d.IEpg.BulkUpdate(iepglist); err != nil {
						app.Api.InternalError(res, req, err)
						return
					} else {
						req.Logger.Debug("Updated %d iepg entries...", len(keys))
						// invalidate cache after 10 seconds
						time.Sleep(10 * time.Second)
						d.GetRecords(true)
						res.WriteJson(map[string]int{
							"updates": len(iepglist),
						})
						return
					}
				}
			},
		))
}
예제 #17
0
func init() {
	app.Api.Get("/keywords/",
		func(res *wcg.Response, req *wcg.Request) {
			var list []*tv.CrawlerConfig
			ctx := gae.NewContext(req)
			mc := memcache.NewDriver(ctx, req.Logger)
			err := mc.CachedObject(MC_KEY_KEYWORDS, &list, func() (interface{}, error) {
				var list []*tv.CrawlerConfig
				d := NewCrawlerConfigDriver(app.Key, ctx, req.Logger)
				q := d.NewQuery().Order("-CreatedAt")
				_, err := q.GetAll(&list)
				if list == nil {
					return make([]*tv.CrawlerConfig, 0), nil
				} else {
					return list, err
				}
			}, req.Query("force") == "1")

			if err != nil {
				lib.InternalError(res, req, err)
			} else {
				res.WriteJson(list)
			}
		},
	)

	app.Api.Get("/keywords/preview/:keyword.json", lib.Family.Required(
		func(res *wcg.Response, req *wcg.Request) {
			var channels []*tv.TvChannel
			ctx := gae.NewContext(req)
			mc := memcache.NewDriver(ctx, req.Logger)
			err := mc.CachedObject(MC_KEY_CHANNELS, &channels, func() (interface{}, error) {
				return NewTvChannelDriver(app.Key, ctx, req.Logger).AllAsList()
			}, false)

			keyword := req.Param("keyword")
			scope, _ := strconv.Atoi(req.Query("scope"))
			list, err := getIEpgListFromCrawlerConfig(res, req, &tv.CrawlerConfig{
				Keyword:  keyword,
				Scope:    scope,
				Category: "dummy",
			}, channels)
			if err != nil {
				lib.InternalError(res, req, err)
			} else {
				res.WriteJson(map[string]interface{}{
					"samples": list,
					"total":   len(list),
				})
			}
		},
	))

	app.Api.Post("/keywords/", lib.Family.Required(
		func(res *wcg.Response, req *wcg.Request) {
			ctx := gae.NewContext(req)
			mc := memcache.NewDriver(ctx, req.Logger)
			d := NewCrawlerConfigDriver(app.Key, ctx, req.Logger)
			scope, _ := strconv.Atoi(req.Form("scope"))
			cfg := &tv.CrawlerConfig{
				Keyword:  req.Form("keyword"),
				Category: req.Form("category"),
				Scope:    scope,
			}
			if err := d.Add(cfg); err != nil {
				app.Api.InternalError(res, req, err)
				return
			} else {
				mc.Delete(MC_KEY_KEYWORDS)
				app.Api.Created(res, req, req.Form("keyword"))
				return
			}
		},
	))

	app.Api.Delete("/keywords/:keyword.json", lib.Family.Required(
		func(res *wcg.Response, req *wcg.Request) {
			ctx := gae.NewContext(req)
			d := NewCrawlerConfigDriver(app.Key, ctx, req.Logger)
			mc := memcache.NewDriver(ctx, req.Logger)
			keyword := req.Param("keyword")
			if err := d.Delete(keyword); err != nil {
				lib.InternalError(res, req, err)
				return
			} else {
				mc.Delete(MC_KEY_KEYWORDS)
				app.Api.Ok(res, req)
				return
			}
		},
	))

}