func setupAPIAPITokens(app *server.App) { var API = app.API() // -------------------------------------------------------------------------- // APIToken API.GET("/api_tokens/", middleware.EntityAll(entities.APIToken.Query())) API.GET("/api_tokens/:token.json", middleware.EntityGet(entities.APIToken.Get().Cache(true), "token")) API.POST("/api_tokens/", middleware.ParseForm(func(v *validators.FormValidator) { v.Field("description").Required() }), middleware.EntityPost(entities.APIToken.Put())) API.PUT("/api_tokens/:token.json", middleware.ParseForm(func(v *validators.FormValidator) { v.Field("description").Required() }), middleware.EntityPut(entities.APIToken.Put(), "token")) API.DELETE("/api_tokens/:token.json", middleware.EntityDelete(entities.APIToken.Delete(), "token")) }
func setupAPIMembers(app *server.App) { var API = app.API() API.GET("/:artist/members/", handlers.ArtistHandler( func(req *wcg.Request, artist *hplink.Artist) response.Response { memberQuery := Member.Query().Order("Index").Filter("ArtistKey=", artist.Key).Cache(fmt.Sprintf(ckAllMembersTemplate, artist.Key)) return middleware.EntityAll(memberQuery)(req) }, )) API.GET("/:artist/members/:member.json", handlers.MemberHandler( func(req *wcg.Request, member *hplink.Member) response.Response { return response.NewJSONResponse(member) }, ), ) API.PUT("/:artist/members/:member.json", handlers.AdminGate, middleware.ParseForm(func(v *validators.FormValidator) { v.Field("color").Required() }), handlers.MemberHandler( func(req *wcg.Request, member *hplink.Member) response.Response { if err := Member.UpdateEntityFromForm(member, req.HTTPRequest().Form); err != nil { req.Logger.Warnf("UpdateEntityFromForm returns and error: %#v", err) return response.APIBadRequest(middleware.ErrInvalidFormParameters) } Member.Put().Cache(ckAllMembersTemplate).MustUpdate(req, member) return response.NewJSONResponse(member) }, ), ) }
func setupAPIIEPGExclusions(app *server.App) { var AsyncAPI = app.AsyncAPI() var API = app.API() API.GET("/iepg/exclusions/", middleware.EntityAll(IEPGExclusion.Query().Cache(_CacheAllIEPGExclusions))) exclusionTask := AsyncAPI.Define("/iepg/exclusions/task/") exclusionTask.Queue.Rate = "1/s" exclusionTask.Queue.MaxConcurrentRequests = "1" exclusionTask.OnTrigger(middleware.Gate("family")) exclusionTask.OnMonitor(middleware.Gate("family")) exclusionTask.OnProcess(server.AsyncTaskHandler( func(req *wcg.Request, t *models.AsyncAPITask) (*models.AsyncAPITaskProgress, error) { var list []*pt.IEPG records := recentRecordsQuery().MustExecute(req).Data.([]pt.IEPG) for i := range records { list = append(list, &records[i]) } if err := applyExclusions(req, list); err != nil { return nil, err } IEPG.PutMulti().Cache(_CacheAllIEPGExclusions).MustUpdate(req, list) return nil, nil }, )) API.POST("/iepg/exclusions/", middleware.Gate("family"), middleware.ParseForm(func(v *validators.FormValidator) { v.Field("cid").Required() v.Field("sid").Required() v.Field("weekday").Required() v.Field("title_text").Required() v.Field("title_text_type").Required() }), middleware.EntityPost(IEPGExclusion.Put().Cache(_CacheAllIEPGExclusions)), ) API.DELETE("/iepg/exclusions/:id.json", middleware.Gate("family"), middleware.EntityDelete(IEPGExclusion.Delete().Cache(_CacheAllIEPGExclusions), "id")) }
func setupAPIChannels(app *server.App) { var API = app.API() API.GET("/channels/", middleware.EntityAll(Channel.Query().Cache(_CacheAllChannels))) API.POST("/channels/", middleware.Gate("family"), middleware.ParseForm(func(v *validators.FormValidator) { v.Field("cid").Required() v.Field("sid").Required() v.Field("name").Required() v.Field("iepg_station_id").Required() }), middleware.EntityPost(Channel.Put().Cache(_CacheAllChannels))) API.DELETE("/channels/:id.json", middleware.Gate("family"), middleware.EntityDelete(Channel.Delete().Cache(_CacheAllChannels), "id")) }
func setupAPIIEPGKeywords(app *server.App) { var API = app.API() API.GET("/iepg/keywords/", middleware.EntityAll(IEPGKeyword.Query().Cache(_CacheAllIEPGKeywords))) API.POST("/iepg/keywords/", middleware.Gate("family"), middleware.ParseForm(func(v *validators.FormValidator) { v.Field("keyword").Required() v.Field("category").Required() v.IntField("scope").Required() }), middleware.EntityPost(IEPGKeyword.Put().Cache(_CacheAllIEPGKeywords))) API.DELETE("/iepg/keywords/:id.json", middleware.Gate("family"), middleware.EntityDelete(IEPGKeyword.Delete().Cache(_CacheAllIEPGKeywords), "id")) API.POST("/iepg/keywords/preview/", middleware.Gate("family"), middleware.ParseForm(func(v *validators.FormValidator) { v.Field("keyword").Required() v.IntField("scope").Required() }), server.Handler( func(req *wcg.Request) response.Response { list, err := crawlKeyword(req, &pt.IEPGKeyword{ Keyword: req.Form("keyword"), Scope: pt.ParseIEPGCrawlerScope(req.Form("scope")), }) if err != nil { return response.InternalServerError(req, err) } return response.NewJSONResponse(map[string]interface{}{ "hits": list, }) }, )) var AsyncAPI = app.AsyncAPI() keywordCrawlTask := AsyncAPI.Define("/iepg/keywords/task/") keywordCrawlTask.Queue.Rate = "1/s" keywordCrawlTask.Queue.MaxConcurrentRequests = "1" keywordCrawlTask.OnTrigger(middleware.Gate("family")) keywordCrawlTask.OnMonitor(middleware.Gate("family")) keywordCrawlTask.OnProcess(server.AsyncTaskHandler( func(req *wcg.Request, t *models.AsyncAPITask) (*models.AsyncAPITaskProgress, error) { data := IEPGKeyword.Query().Cache(_CacheAllIEPGKeywords).MustExecute(req).Data if data == nil { return nil, nil } var keywords = data.([]pt.IEPGKeyword) req.Logger.Infof("Crawling %d keywords", len(keywords)) for _, key := range keywords { list, err := crawlKeyword(req, &key) if err != nil { return nil, err } IEPG.PutMulti().Cache(_CacheAllIEPGKeywords).MustUpdate(req, list) } return nil, nil }, )) keywordCrawlTask.ScheduleCron( "Crawl IEPG keywords", "every 1 hours", ) }
func setupAPIOAuth2(app *server.App) { var API = app.API() API.GET("/oauth2/clients/", middleware.EntityAll(entities.OAuth2ClientSettings.Query())) API.GET("/oauth2/clients/:key.json", middleware.EntityGet(entities.OAuth2ClientSettings.Get().Cache(true), "key")) // Create an oauth2.Config object into session and redirect to the oauth2 endpoint. // /admin/oauth2/callback.html will finally authorize the callback code and store the oauth2.Config into datastore. API.POST("/oauth2/clients/", middleware.ParseForm(func(v *validators.FormValidator) { v.Field("key").Required() v.Field("client_id").Required() v.Field("client_secret").Required() v.Field("auth_url").Required() v.Field("token_url").Required() }), server.Handler(func(req *wcg.Request) response.Response { cfg := &oauth2.Config{ ClientID: req.Form("client_id"), ClientSecret: req.Form("client_secret"), Endpoint: oauth2.Endpoint{ AuthURL: req.Form("auth_url"), TokenURL: req.Form("token_url"), }, Scopes: strings.Split(req.Form("scopes"), ","), RedirectURL: wcg.AbsoluteURL( req, fmt.Sprintf("/api/admin/oauth2/callback/?oauth2_key=%s", req.Form("key")), ), } data := wcg.DataBag{} data.Set("key", req.Form("key")) data.Set("client_id", cfg.ClientID) data.Set("client_secret", cfg.ClientSecret) data.Set("auth_url", cfg.Endpoint.AuthURL) data.Set("token_url", cfg.Endpoint.TokenURL) data.Set("scopes", req.Form("scopes")) data.Set("redirect_url", cfg.RedirectURL) req.Session.SetData( fmt.Sprintf("admin.oauth2_%s", req.Form("key")), data, ) return response.NewRedirect(cfg.AuthCodeURL("state", oauth2.AccessTypeOffline), response.RedirectSeeOther) })) API.DELETE("/oauth2/clients/:client_id.json", middleware.EntityDelete(entities.OAuth2ClientSettings.Delete(), "client_id")) API.GET("/oauth2/callback/", server.Handler(func(req *wcg.Request) response.Response { key := req.Query("oauth2_key") code := req.Query("code") data, ok := req.Session.GetData(fmt.Sprintf("admin.oauth2_%s", key)) if !ok { return response.NotFound(req) } scopes, _ := data.Get("scopes") cfg := &oauth2.Config{} cfg.ClientID, _ = data.Get("client_id") cfg.ClientSecret, _ = data.Get("client_secret") cfg.Endpoint.AuthURL, _ = data.Get("auth_url") cfg.Endpoint.TokenURL, _ = data.Get("token_url") cfg.Scopes = strings.Split(scopes, ",") cfg.RedirectURL, _ = data.Get("redirect_url") token, err := cfg.Exchange(gae.NewContext(req), code) if err != nil { return response.BadRequest(req, err) } settings := models.NewOAuth2ClientSettings(cfg, token) settings.Key = key entities.OAuth2ClientSettings.Put().Key(key).MustUpdate(req, settings) return response.NewRedirect("/admin/oauth2/", response.RedirectSeeOther) })) }
func setupAPICrawlerSettings(app *server.App) { var API = app.API() var urlValidator = server.Handler(func(req *wcg.Request) response.Response { _, err := url.Parse(req.Param("url")) if err != nil { return response.APINotFound } return nil }) API.GET("/crawlersettings/:type/", middleware.EntityAll(CrawlerSettings.Query().Filter("Type=", request.Value(func(req *wcg.Request) interface{} { t, _ := hplink.ParseCrawlerSettingsType(req.Param("type")) if t == hplink.CrawlerSettingsTypeUnknown { return entities.FilterValueSkip } return t }))), ) API.GET("/crawlersettings/ameblo/stats/", server.Handler(func(req *wcg.Request) response.Response { type post struct { URL string `json:"url"` At time.Time `json:"at"` } type stats struct { URL string `json:"url"` FirstPost *post `json:"first_post,omitempty"` LastPost *post `json:"last_post,omitempty"` TotalPosts int `json:"total_posts"` CrawledPosts int `json:"crawled_posts"` ImageFailurePosts int `json:"image_failure_posts"` } p := CrawlerSettings.Query().Filter("Type=", hplink.CrawlerSettingsTypeAmeblo).MustExecute(req) settings := p.Data.([]hplink.CrawlerSettings) s := make([]stats, len(settings)) if err := iterator.ParallelSlice(settings, func(i int, v *hplink.CrawlerSettings) error { s[i].URL = v.URL s[i].TotalPosts = AmebloPost.Query().Filter("SettingsURL=", v.URL).MustCount(req) if s[i].TotalPosts > 0 { s[i].CrawledPosts = AmebloPost.Query().Filter("SettingsURL=", v.URL).Filter("IsContentsCrawled=", true).MustCount(req) s[i].ImageFailurePosts = AmebloPost.Query().Filter("SettingsURL=", v.URL).Filter("Images.Height=", 0).MustCount(req) pf := AmebloPost.Query().Filter("SettingsURL=", v.URL).Order("PostAt").Limit(1).MustExecute(req) pl := AmebloPost.Query().Filter("SettingsURL=", v.URL).Order("-PostAt").Limit(1).MustExecute(req) first := pf.Head().(*hplink.AmebloPost) last := pl.Head().(*hplink.AmebloPost) s[i].FirstPost = &post{ URL: first.URL, At: first.PostAt, } s[i].LastPost = &post{ URL: last.URL, At: last.PostAt, } return nil } return nil }); err != nil { panic(err) } return response.NewJSONResponse(s) }), ) API.GET("/crawlersettings/:url.json", middleware.EntityGet(CrawlerSettings.Get(), "url"), ) API.PUT("/crawlersettings/:url.json", urlValidator, middleware.ParseForm(func(v *validators.FormValidator) { v.Field("artist_key").Required() }), middleware.EntityPutOrCreate( CrawlerSettings.Put(), "url", ), ) API.DELETE("/crawlersettings/:url.json", urlValidator, middleware.EntityDelete(CrawlerSettings.Delete(), "url"), ) }
func setupAPIStats(app *server.App) { var API = app.API() API.GET("/stats/servers/", middleware.EntityAll(Server.Query())) API.GET("/stats/nasdisks/", middleware.EntityAll(NASDisk.Query())) API.GET("/stats/servers/:server/:stats/", server.Handler( func(req *wcg.Request) response.Response { key, _ := Server.Get().Key(req.Param("server")).Cache(true).MustOne(req) if key == nil { req.Logger.Debugf("server %q is not found.", req.Param("server")) return response.NotFound(req) } var kind *entities.Kind switch req.Param("stats") { case "system": kind = SystemStats break case "cpu": kind = CPUStats break case "memory": kind = MemoryStats break case "disk": kind = DiskStats break case "filesystem": kind = FileSystemStats break case "network": kind = NetworkStats break default: req.Logger.Debugf("metric %q is invalid.", req.Param("stats")) return response.NotFound(req) } return execStatsQuery(req, kind.Query().Ancestor(key)) }, )) API.POST("/stats/metrics/", middleware.APITokenOnly(), server.Handler( func(req *wcg.Request) response.Response { ent, err := SystemMetric.CreateEntitiesFromJSON(req.HTTPRequest().Body) if err != nil { return response.BadRequest(req, err) } collection := home.NewStatsFromMetrics(ent.([]*home.SystemMetric)) if len(collection) == 0 { return response.BadRequest(req, fmt.Errorf("No stats are collected.")) } if collection[0].System.ServerName == "" { return response.BadRequest(req, fmt.Errorf("server_name is missing")) } for _, stats := range collection { key := getServerKey(req, stats.System.ServerName) id := fmt.Sprintf("%s.%d", key.StringID(), stats.Timestamp.Unix()) stats.System.ID = id stats.CPU.ID = id stats.Memory.ID = id for _, v := range stats.Disks { v.ID = fmt.Sprintf("%s.%s.%d", key.StringID(), v.DeviceName, stats.Timestamp.Unix()) } for _, v := range stats.Networks { v.ID = fmt.Sprintf("%s.%s.%d", key.StringID(), v.DeviceName, stats.Timestamp.Unix()) } SystemStats.Put().Parent(key).MustUpdate(req, stats.System) CPUStats.Put().Parent(key).MustUpdate(req, stats.CPU) MemoryStats.Put().Parent(key).MustUpdate(req, stats.Memory) DiskStats.PutMulti().Parent(key).MustUpdate(req, stats.Disks) NetworkStats.PutMulti().Parent(key).MustUpdate(req, stats.Networks) } return response.NewJSONResponse(true) }, )) API.POST("/stats/filesystem/", middleware.APITokenOnly(), server.Handler( func(req *wcg.Request) response.Response { ent, err := FileSystemStats.CreateEntitiesFromJSON(req.HTTPRequest().Body) if err != nil { return response.BadRequest(req, err) } filesystems := ent.([]*home.FileSystemStats) if filesystems[0].ServerName == "" { return response.BadRequest(req, fmt.Errorf("server_name is missing")) } key := getServerKey(req, filesystems[0].ServerName) for _, fs := range filesystems { fs.ID = fmt.Sprintf("%s.%s.%d", fs.ServerName, fs.Name, fs.Timestamp.Unix()) } FileSystemStats.PutMulti().Parent(key).MustUpdate(req, filesystems) return response.NewJSONResponse(true) }, )) API.POST("/stats/smart/", middleware.APITokenOnly(), server.Handler( func(req *wcg.Request) response.Response { ent, err := SMARTStats.CreateEntitiesFromJSON(req.HTTPRequest().Body) if err != nil { return response.BadRequest(req, err) } smartstats := ent.([]*home.SMARTStats) if smartstats[0].Serial == "" { return response.BadRequest(req, fmt.Errorf("serial is missing")) } key := getNASDiskKey(req, smartstats[0].Serial) for _, smart := range smartstats { smart.ID = fmt.Sprintf("%s.%d", smart.Serial, smart.Timestamp.Unix()) } SMARTStats.PutMulti().Parent(key).MustUpdate(req, smartstats) return response.NewJSONResponse(true) }, )) }