// Read handles GET func (ctl *SiteReservedController) Read(c *models.Context) { host, exists := c.RouteVars["subdomain"] if !exists { c.RespondWithErrorMessage("No subdomain query specified", http.StatusBadRequest) return } reserved, err := models.IsReservedSubdomain(host) if err != nil { c.RespondWithErrorMessage(err.Error(), http.StatusInternalServerError) return } var responseBody string if reserved { responseBody = `{"reserved":true}` c.ResponseWriter.Header().Set("Content-Length", strconv.Itoa(len(responseBody))) } else { responseBody = `{"reserved":false}` c.ResponseWriter.Header().Set("Content-Length", strconv.Itoa(len(responseBody))) } c.ResponseWriter.Header().Set("Content-Type", "application/json") c.ResponseWriter.Header().Set("Access-Control-Allow-Origin", "*") c.ResponseWriter.WriteHeader(http.StatusOK) c.ResponseWriter.Write([]byte(responseBody)) }
// Update handles PUT func (ctl *IgnoredController) Update(c *models.Context) { m := models.IgnoreType{} err := c.Fill(&m) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("The post data is invalid: %v", err.Error()), http.StatusBadRequest, ) return } if c.Auth.ProfileID < 1 { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } m.ProfileID = c.Auth.ProfileID status, err := m.Update() if err != nil { c.RespondWithErrorDetail(err, status) return } c.RespondWithOK() }
// Delete handles DELETE func (ctl *ProfileController) Delete(c *models.Context) { // Right now no-one can delete as it would break attribution // of things like Comments c.RespondWithNotImplemented() return /* _, itemTypeID, itemID, status, err := c.GetItemTypeAndItemID() if err != nil { c.RespondWithErrorDetail(err, status) } m := models.ProfileType{} m.Id = itemID status, err := m.Delete() if err != nil { c.RespondWithErrorDetail(err, status) return } audit.Replace( c.Site.ID, h.ItemTypes[h.ItemTypeProfile], m.Id, c.Auth.ProfileID, time.Now(), c.IP, ) c.RespondWithOK() */ }
// Delete handles DELETE func (ctl *MenuController) Delete(c *models.Context, siteID int64) { // Start :: Auth site, status, err := models.GetSite(siteID) if err != nil { c.RespondWithErrorDetail(err, status) return } // Use the user ID to check, since the current context is a different site (the root site) // than the site the owner profile is associated with. owner, status, err := models.GetProfileSummary(site.ID, site.OwnedByID) if err != nil { c.RespondWithErrorDetail(err, status) return } if owner.UserID != c.Auth.UserID { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } // End :: Auth status, err = models.DeleteMenu(siteID) if err != nil { c.RespondWithErrorDetail(err, status) return } c.RespondWithOK() }
// Read handles GET func (ctl *PermissionController) Read(c *models.Context) { ac, status, err := GetAuthContext(c) if err != nil { c.RespondWithErrorDetail(err, status) return } m := models.GetPermission(ac) c.RespondWithData(m) }
// Read handles GET func (ctl *MenuController) Read(c *models.Context, siteID int64) { ems, status, err := models.GetMenu(siteID) if err != nil { c.RespondWithErrorDetail(err, status) return } c.RespondWithData(ems) }
// Read handles GET func (ctl *GeoCodeController) Read(c *models.Context) { c.ResponseWriter.Header().Set("Content-Type", "application/json") // Debugging info dur := time.Now().Sub(c.StartTime) place := strings.Trim(c.Request.URL.Query().Get("q"), " ") if strings.Trim(c.Request.URL.Query().Get("q"), " ") == "" { ctl.Error(c, "query needed", http.StatusBadRequest) return } if c.Auth.ProfileID <= 0 { ctl.Error(c, "no auth", http.StatusForbidden) return } u, _ := url.Parse("http://open.mapquestapi.com/nominatim/v1/search.php") q := u.Query() q.Set("format", "json") // We are not interested in the array returned, just the best match which is the first response q.Set("limit", "1") q.Set("q", place) u.RawQuery = q.Encode() resp, err := http.Get(u.String()) if err != nil { ctl.Error(c, err.Error(), http.StatusInternalServerError) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { ctl.Error(c, err.Error(), http.StatusInternalServerError) return } // Again, not interested in the outer array [], so we substring that out t := string(body) t = t[1 : len(t)-1] // But if we now have nothing (no matches were found, we need to return an empty object) if strings.Trim(t, ` `) == `` { t = `{}` } body = []byte(t) // Return our JavaScript object contentLength := len(body) c.ResponseWriter.Header().Set("Content-Length", strconv.Itoa(contentLength)) go models.SendUsage(c, http.StatusOK, contentLength, dur, []string{}) c.WriteResponse([]byte(body), http.StatusOK) }
// ReadMany handles GET func (ctl *EventsController) ReadMany(c *models.Context) { // Start Authorisation perms := models.GetPermission( models.MakeAuthorisationContext( c, 0, h.ItemTypes[h.ItemTypeEvent], 0), ) if !perms.CanRead { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } // End Authorisation // Fetch query string args if any exist query := c.Request.URL.Query() limit, offset, status, err := h.GetLimitAndOffset(query) if err != nil { c.RespondWithErrorDetail(err, status) return } attending, status, err := h.GetAttending(query) if err != nil { c.RespondWithErrorDetail(err, status) return } ems, total, pages, status, err := models.GetEvents(c.Site.ID, c.Auth.ProfileID, attending, limit, offset) if err != nil { c.RespondWithErrorDetail(err, status) return } // Construct the response thisLink := h.GetLinkToThisPage(*c.Request.URL, offset, limit, total) m := models.EventsType{} m.Events = h.ConstructArray( ems, h.APITypeEvent, total, limit, offset, pages, c.Request.URL, ) m.Meta.Links = []h.LinkType{ h.LinkType{Rel: "self", Href: thisLink.String()}, } m.Meta.Permissions = perms c.RespondWithData(m) }
// Read handles GET func (ctl *AuthController) Read(c *models.Context) { // Extract access token from request and retrieve its metadata m, status, err := models.GetAccessToken(c.RouteVars["id"]) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Error retrieving access token: %v", err.Error()), status, ) return } c.RespondWithData(m) }
// Error is a generic error handler for the Geo controller func (ctl *GeoCodeController) Error(c *models.Context, message string, status int) { errorJSON := `{"error":["` + message + `"]}` contentLength := len(errorJSON) c.ResponseWriter.Header().Set("Content-Length", strconv.Itoa(contentLength)) dur := time.Now().Sub(c.StartTime) go models.SendUsage(c, status, contentLength, dur, []string{"message"}) c.WriteResponse([]byte(errorJSON), status) return }
// Read handles GET func (ctl *SearchController) Read(c *models.Context) { results, status, err := models.Search( c.Site.ID, *c.Request.URL, c.Auth.ProfileID, ) if err != nil { c.RespondWithErrorDetail(err, status) return } c.RespondWithData(results) }
// Create handles GET func (ctl *MicrocosmsController) Create(c *models.Context) { // Validate inputs m := models.MicrocosmType{} err := c.Fill(&m) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("The post data is invalid: %v", err.Error()), http.StatusBadRequest, ) return } // Start : Authorisation perms := models.GetPermission( models.MakeAuthorisationContext(c, 0, h.ItemTypes[h.ItemTypeSite], c.Site.ID), ) if !perms.CanCreate { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } // End : Authorisation // Populate where applicable from auth and context m.SiteID = c.Site.ID m.Meta.CreatedByID = c.Auth.ProfileID m.Meta.Created = time.Now() m.OwnedByID = c.Auth.ProfileID status, err := m.Insert() if err != nil { c.RespondWithErrorDetail(err, status) return } audit.Create( c.Site.ID, h.ItemTypes[h.ItemTypeMicrocosm], m.ID, c.Auth.ProfileID, time.Now(), c.IP, ) c.RespondWithSeeOther( fmt.Sprintf( "%s/%d", h.APITypeMicrocosm, m.ID, ), ) }
// Update handles PUT func (ctl *ProfileOptionsController) Update(c *models.Context) { var m = models.ProfileOptionType{} err := c.Fill(&m) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("The post data is invalid: %v", err.Error()), http.StatusBadRequest, ) return } // Profile ID cannot be changed m.ProfileID = c.Auth.ProfileID status, err := m.Update() if err != nil { c.RespondWithErrorDetail(err, status) return } audit.Update( c.Site.ID, h.ItemTypes[h.ItemTypeProfile], m.ProfileID, c.Auth.ProfileID, time.Now(), c.IP, ) // Respond c.RespondWithSeeOther( fmt.Sprintf("/api/v1/profiles/options"), ) }
// Read handles GET either by /site or /sites/{site_id} func (ctl *SiteController) Read(c *models.Context) { // Check whether this site is being accessed by ID siteQuery, exists := c.RouteVars["site_id"] if exists { siteID, err := strconv.ParseInt(siteQuery, 10, 64) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("The supplied site ID ('%s') is not a number.", siteQuery), http.StatusBadRequest, ) return } site, status, err := models.GetSite(siteID) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("No site with ID %d found", siteID), status, ) return } c.RespondWithData(site) return } // Site already populated in context, so only fetch permissions c.Site.Meta.Permissions = models.GetPermission( models.MakeAuthorisationContext( c, 0, h.ItemTypes[h.ItemTypeSite], c.Site.ID), ) c.RespondWithData(c.Site) return }
// ReadMany handles GET for the collection func (ctl *AttachmentsController) ReadMany(c *models.Context) { itemTypeID, itemID, perms, status, err := ParseItemInfo(c) if err != nil { c.RespondWithErrorDetail(err, status) return } if !perms.CanRead { c.RespondWithErrorMessage( h.NoAuthMessage, http.StatusForbidden, ) return } query := c.Request.URL.Query() limit, offset, status, err := h.GetLimitAndOffset(query) if err != nil { c.RespondWithErrorDetail(err, status) return } attachments, total, pages, status, err := models.GetAttachments(itemTypeID, itemID, limit, offset) if err != nil { c.RespondWithErrorDetail(err, status) return } thisLink := h.GetLinkToThisPage(*c.Request.URL, offset, limit, total) m := models.AttachmentsType{} m.Attachments = h.ConstructArray( attachments, h.APITypeAttachment, total, limit, offset, pages, c.Request.URL, ) m.Meta.Links = []h.LinkType{ h.LinkType{Rel: "self", Href: thisLink.String()}, } m.Meta.Permissions = perms c.RespondWithData(m) }
// Read handles GET func (ctl *UpdateOptionController) Read(c *models.Context) { if c.Auth.ProfileID < 1 { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } _, _, itemID, status, err := c.GetItemTypeAndItemID() if err != nil { c.RespondWithErrorDetail(err, status) return } m, status, err := models.GetUpdateOptionByUpdateType(c.Auth.ProfileID, itemID) if err != nil { c.RespondWithErrorDetail(err, status) return } c.RespondWithData(m) }
// Read handles GET func (ctl *FileController) Read(c *models.Context) { fileHash := c.RouteVars["fileHash"] if fileHash == "" { c.RespondWithErrorMessage( fmt.Sprintf("The supplied file hash cannot be zero characters: %s", c.RouteVars["fileHash"]), http.StatusBadRequest, ) return } fileBytes, headers, _, err := models.GetFile(fileHash) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Could not retrieve file: %v", err.Error()), http.StatusInternalServerError, ) return } oneYear := time.Hour * 24 * 365 nextYear := time.Now().Add(oneYear) c.ResponseWriter.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", oneYear/time.Second)) c.ResponseWriter.Header().Set("Expires", nextYear.Format(time.RFC1123)) for h, v := range headers { c.ResponseWriter.Header().Set(h, v) } c.WriteResponse(fileBytes, http.StatusOK) return }
// ReadMany handles GET for the collection func (ctl *TrendingController) ReadMany(c *models.Context) { limit, offset, status, err := h.GetLimitAndOffset(c.Request.URL.Query()) if err != nil { c.RespondWithErrorDetail(err, status) return } trending, total, pages, status, err := models.GetTrending(c.Site.ID, c.Auth.ProfileID, limit, offset) if err != nil { c.RespondWithErrorDetail(err, status) return } response := models.TrendingItems{} response.Items = h.ConstructArray( trending, "items", total, limit, offset, pages, c.Request.URL, ) thisLink := h.GetLinkToThisPage(*c.Request.URL, offset, limit, total) response.Meta.Links = []h.LinkType{ h.LinkType{Rel: "self", Href: thisLink.String()}, } c.RespondWithData(response) }
// Delete handles DELETE func (ctl *AuthController) Delete(c *models.Context) { // Extract access token from request and delete its record m, status, err := models.GetAccessToken(c.RouteVars["id"]) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Error retrieving access token: %v", err.Error()), status, ) return } status, err = m.Delete() if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("Error deleting access token: %v", err.Error()), status, ) return } audit.Delete( c.Site.ID, h.ItemTypes[h.ItemTypeAuth], m.UserID, c.Auth.ProfileID, time.Now(), c.IP, ) c.RespondWithOK() }
// ReadMany handles GET for a collection func (ctl *SitesController) ReadMany(c *models.Context) { limit, offset, status, err := h.GetLimitAndOffset(c.Request.URL.Query()) if err != nil { c.RespondWithErrorDetail(err, status) return } var userID int64 // Passing ?filter=owned returns sites owned by logged-in user. if c.Request.FormValue("filter") == "owned" { if c.Auth.UserID == 0 { c.RespondWithErrorMessage( fmt.Sprintf("You must be logged in to list your own sites"), http.StatusForbidden, ) return } userID = c.Auth.UserID } // Passing 0 as userID means return all sites. ems, total, pages, status, err := models.GetSites(userID, limit, offset) if err != nil { c.RespondWithErrorDetail(err, status) return } thisLink := h.GetLinkToThisPage(*c.Request.URL, offset, limit, total) m := models.SitesType{} m.Sites = h.ConstructArray( ems, h.APITypeSite, total, limit, offset, pages, c.Request.URL, ) m.Meta.Links = []h.LinkType{ h.LinkType{Rel: "self", Href: thisLink.String()}, } c.RespondWithData(m) }
// Read handles GET func (ctl *SiteHostController) Read(c *models.Context) { host, exists := c.RouteVars["host"] if !exists { c.RespondWithErrorMessage("No host query specified", http.StatusBadRequest) return } // This could be further optimised by only caching host -> microcosm subdomain. site, status, err := models.GetSiteByDomain(host) if err != nil { c.RespondWithErrorDetail(err, status) return } microcosmHost := site.SubdomainKey + ".microco.sm" contentLen := len(microcosmHost) c.ResponseWriter.Header().Set("Content-Length", strconv.Itoa(contentLen)) c.ResponseWriter.Header().Set("Content-Type", "text/plain") c.ResponseWriter.Header().Set("X-Microcosm-Host", microcosmHost) // Calling Write automatically sets HTTP status code to 200. c.ResponseWriter.Write([]byte(microcosmHost)) }
// Delete handles DELETE func (ctl *AttributeController) Delete(c *models.Context) { _, itemTypeID, itemID, status, err := c.GetItemTypeAndItemID() if err != nil { c.RespondWithErrorDetail(err, status) return } key := c.RouteVars["key"] m := models.AttributeType{} m.Key = key attributeID, status, err := models.GetAttributeID(itemTypeID, itemID, m.Key) if err != nil { c.RespondWithErrorDetail(err, status) return } m.ID = attributeID status, err = m.Delete() if err != nil { c.RespondWithErrorDetail(err, status) return } audit.Delete( c.Site.ID, h.ItemTypes[h.ItemTypeAttribute], m.ID, c.Auth.ProfileID, time.Now(), c.IP, ) c.RespondWithOK() }
// ReadMany handles GET for the collection func (ctl *WatchersController) ReadMany(c *models.Context) { if c.Auth.ProfileID < 1 { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } query := c.Request.URL.Query() limit, offset, status, err := h.GetLimitAndOffset(query) if err != nil { c.RespondWithErrorDetail(err, status) return } ems, total, pages, status, err := models.GetProfileWatchers( c.Auth.ProfileID, c.Site.ID, limit, offset, ) if err != nil { c.RespondWithErrorDetail(err, status) return } // Construct the response thisLink := h.GetLinkToThisPage(*c.Request.URL, offset, limit, total) m := models.WatchersType{} m.Watchers = h.ConstructArray( ems, h.APITypeWatcher, total, limit, offset, pages, c.Request.URL, ) m.Meta.Links = []h.LinkType{ h.LinkType{Rel: "self", Href: thisLink.String()}, } c.RespondWithData(m) }
// ReadMany handles GET func (ctl *AttendeesCSVController) ReadMany(c *models.Context) { eventID, err := strconv.ParseInt(c.RouteVars["event_id"], 10, 64) if err != nil { c.RespondWithErrorMessage( fmt.Sprintf("The supplied event_id ('%s') is not a number.", c.RouteVars["event_id"]), http.StatusBadRequest, ) return } // Start Authorisation perms := models.GetPermission( models.MakeAuthorisationContext( c, 0, h.ItemTypes[h.ItemTypeEvent], eventID), ) if !perms.CanRead { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } if !(perms.IsOwner || perms.IsModerator || perms.IsSiteOwner) { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } // End Authorisation attendees, status, err := models.GetAttendeesCSV(c.Site.ID, eventID, c.Auth.ProfileID) if err != nil { c.RespondWithErrorDetail(err, status) return } c.ResponseWriter.Header().Set(`Cache-Control`, `no-cache, max-age=0`) c.ResponseWriter.Header().Set(`Vary`, `Authorization`) c.ResponseWriter.Header().Set(`Content-Type`, `text/csv`) c.ResponseWriter.Header().Set(`Content-Disposition`, fmt.Sprintf(`attachment; filename=event%d.csv`, eventID)) c.WriteResponse([]byte(attendees), http.StatusOK) }
// Read handles GET func (ctl *Redirect404Controller) Read(c *models.Context) { // Just call this with authentication (if you have it) and pass in the // unknown URL as a GET param: // // https://dev1.microco.sm/api/v1/resolve?url=http%3A%2F%2Fwww.lfgss.com%2Fforumdisplay.php%3Ff%3D1 // // The URL in the GET param should be URL encoded to ensure that if it has // any querystring, nothing goes awry. An example querystring URL might be: // // http://www.lfgss.com/private.php?t=7865&page=32 // // If you don't get a page/offset back from this, then you haven't URL encoded // it. u := c.Request.URL q := u.Query() inURL := q.Get("url") if inURL == "" { c.RespondWithError(http.StatusBadRequest) return } c.RespondWithData(resolver.Resolve(c.Site.ID, inURL, c.Auth.ProfileID)) }
// ReadMany handles GET func (ctl *IgnoredController) ReadMany(c *models.Context) { if c.Auth.ProfileID < 1 { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } limit, offset, status, err := h.GetLimitAndOffset(c.Request.URL.Query()) if err != nil { c.RespondWithErrorDetail(err, status) return } ems, total, pages, status, err := models.GetIgnored( c.Site.ID, c.Auth.ProfileID, limit, offset, ) if err != nil { c.RespondWithErrorDetail(err, status) return } thisLink := h.GetLinkToThisPage(*c.Request.URL, offset, limit, total) m := models.IgnoredType{} m.Ignored = h.ConstructArray( ems, `/api/v1/ignored`, total, limit, offset, pages, c.Request.URL, ) m.Meta.Links = []h.LinkType{ h.LinkType{ Rel: "self", Href: thisLink.String(), }, } c.RespondWithData(m) }
// Read handles GET func (ctl *ProfileOptionsController) Read(c *models.Context) { if c.Auth.ProfileID < 1 { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } m, status, err := models.GetProfileOptions(c.Auth.ProfileID) if err != nil { c.RespondWithErrorDetail(err, status) return } c.RespondWithData(m) }
// ReadMany handles GET for a collection func (ctl *UpdateOptionsController) ReadMany(c *models.Context) { if c.Auth.ProfileID < 1 { c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden) return } prefs, status, err := models.GetUpdateOptions(c.Site.ID, c.Auth.ProfileID) if err != nil { c.RespondWithErrorDetail(err, status) return } c.RespondWithData(prefs) }
// Read handles GET func (ctl *RedirectController) Read(c *models.Context) { redirect, status, err := redirector.GetRedirect(c.RouteVars["short_url"]) if err != nil { if status == http.StatusNotFound { c.RespondWithErrorMessage( fmt.Sprintf("%v", err.Error()), http.StatusNotFound, ) return } c.RespondWithErrorMessage( fmt.Sprintf("Could not retrieve redirect: %v", err.Error()), http.StatusInternalServerError, ) return } c.RespondWithLocation(redirect.URL) }
// ReadMany handles GET func (ctl *MicrocosmsController) ReadMany(c *models.Context) { perms := models.GetPermission( models.MakeAuthorisationContext(c, 0, h.ItemTypes[h.ItemTypeSite], c.Site.ID), ) // Fetch query string args if any exist limit, offset, status, err := h.GetLimitAndOffset(c.Request.URL.Query()) if err != nil { c.RespondWithErrorDetail(err, status) return } // Fetch list of microcosms ems, total, pages, status, err := models.GetMicrocosms(c.Site.ID, c.Auth.ProfileID, limit, offset) if err != nil { c.RespondWithErrorDetail(err, status) return } // Construct the response thisLink := h.GetLinkToThisPage(*c.Request.URL, offset, limit, total) m := models.MicrocosmsType{} m.Microcosms = h.ConstructArray( ems, h.APITypeMicrocosm, total, limit, offset, pages, c.Request.URL, ) m.Meta.Links = []h.LinkType{ h.LinkType{Rel: "self", Href: thisLink.String()}, } m.Meta.Permissions = perms c.RespondWithData(m) }