Esempio n. 1
0
// 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()
}
Esempio n. 2
0
// 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
}
Esempio n. 3
0
// Update handles PUT
func (ctl *SiteController) Update(c *models.Context) {
	_, _, itemID, status, err := c.GetItemTypeAndItemID()
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	m, status, err := models.GetSite(itemID)
	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(m.ID, m.OwnedByID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	if owner.UserID != c.Auth.UserID {
		c.RespondWithErrorMessage(
			fmt.Sprintf("You must be the owner of the site to update it"),
			http.StatusForbidden,
		)
		return
	}

	err = c.Fill(&m)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("The post data is invalid: %v", err.Error()),
			http.StatusBadRequest,
		)
		return
	}

	status, err = m.Update()
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	audit.Replace(
		c.Site.ID,
		h.ItemTypes[h.ItemTypeSite],
		m.ID,
		c.Auth.ProfileID,
		time.Now(),
		c.IP,
	)

	c.RespondWithSeeOther(fmt.Sprintf("%s/%d", h.APITypeSite, m.ID))
}
Esempio n. 4
0
// Read handles GET
func (ctl *SiteCheckController) Read(c *models.Context) {
	_, _, itemID, status, err := c.GetItemTypeAndItemID()
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	m, status, err := models.GetSite(itemID)
	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(m.ID, m.OwnedByID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	if owner.UserID != c.Auth.UserID {
		c.RespondWithErrorMessage(
			fmt.Sprintf("You must be the owner of the site to view its status"),
			http.StatusForbidden,
		)
		return
	}

	siteHealth, status, err := models.CheckSiteHealth(m)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("Error checking site status: %s", err.Error()),
			status,
		)
		return
	}

	glog.Infof("Got site health: %+v\n", siteHealth)

	c.RespondWithData(siteHealth)
}
Esempio n. 5
0
// Update handles PUT
func (ctl *MenuController) Update(c *models.Context, siteID int64) {
	ems := []h.LinkType{}

	// 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

	err = c.Fill(&ems)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("The post data is invalid: %v", err.Error()),
			http.StatusBadRequest,
		)
		return
	}

	status, err = models.UpdateMenu(siteID, ems)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	c.RespondWithOK()
}
Esempio n. 6
0
func resolveVbulletinURL(redirect Redirect, profileID int64) Redirect {

	// Query string checks are cheap, so we do those first
	qs := redirect.ParsedURL.Query()

	for _, q := range vbqs {
		i := atoi64(qs.Get(q.key))
		if i > 0 {
			i = getNewID(redirect.Origin.OriginID, q.itemTypeID, i)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}

			redirect.ItemTypeID = q.itemTypeID
			redirect.ItemID = i

			break
		}
	}

	i := atoi64(qs.Get("page"))
	if i > 0 {
		switch redirect.ItemTypeID {
		case h.ItemTypes[h.ItemTypeConversation]:
			redirect.Offset = pageToOffset(i, vbPostsPerThreadPage)
		case h.ItemTypes[h.ItemTypeMicrocosm]:
			redirect.Offset = pageToOffset(i, vbThreadsPerForumPage)
		default:
			redirect.Offset = pageToOffset(i, vbPostsPerThreadPage)
		}
	}

	action := qs.Get("goto")
	if action != "" {
		switch action {
		case "newpost":
			action = ActionNewComment
		default:
		}
	}

	// Move on to path based searches, but only if we haven't found anything.
	// These are potentially expensive, so these are ordered by the most likely
	// to the least likely... threads first, posts next, forums after, and then
	// the rest.

	// Look at the URL itself
	path := redirect.ParsedURL.Path

	// Thread redirects
	if redirect.ItemTypeID == 0 {
		matches := vbLastPostInThread.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeConversation]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
			redirect.Action = ActionNewComment
		}
	}

	if redirect.ItemTypeID == 0 {
		matches := vbNewPostInThread.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeConversation]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
			redirect.Action = ActionNewComment
		}
	}

	if redirect.ItemTypeID == 0 {
		matches := vbThreadPrintPage.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeConversation]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
			redirect.Offset = pageToOffset(atoi64(matches[2]), vbPostsPerThreadPage)
		}
	}

	if redirect.ItemTypeID == 0 {
		matches := vbThreadPrint.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeConversation]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
		}
	}

	if redirect.ItemTypeID == 0 {
		matches := vbThreadPage.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeConversation]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i

			// This is no longer done, we just send people to the first page
			// This is due to a massive increase in errors as it turned out there
			// were a lot of bad links in people's posts that vBulletin was more
			// forgiving about (it would auto-send people to the last page)
			//redirect.Offset = pageToOffset(atoi64(matches[2]), vbPostsPerThreadPage)
		}
	}

	if redirect.ItemTypeID == 0 {
		matches := vbThread.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeConversation]

			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
		}
	}

	// Comment redirects
	if redirect.ItemTypeID == 0 {
		matches := vbPostPosition.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeComment]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
			redirect.Action = ActionCommentInContext
		}
	}

	if redirect.ItemTypeID == 0 {
		matches := vbPost.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeComment]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
			redirect.Action = ActionCommentInContext
		}
	}

	// Microcosm redirects
	if redirect.ItemTypeID == 0 {
		matches := vbForumPage.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeMicrocosm]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
			redirect.Offset = pageToOffset(atoi64(matches[2]), vbThreadsPerForumPage)
		}
	}

	if redirect.ItemTypeID == 0 {
		matches := vbForum.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeMicrocosm]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
		}
	}

	if redirect.ItemTypeID == 0 {
		matches := vbAnnouncement.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeMicrocosm]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
		}
	}

	// Profile redirects
	if redirect.ItemTypeID == 0 {
		matches := vbMemberListLetter.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeProfile]
			redirect.Action = ActionSearch
			redirect.Search = matches[1]
		}
	}

	if redirect.ItemTypeID == 0 {
		matches := vbMember.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeProfile]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
		}
	}

	// Attachment redirects
	if redirect.ItemTypeID == 0 {
		matches := vbAttachment.FindStringSubmatch(path)
		if len(matches) > 0 {
			redirect.ItemTypeID = h.ItemTypes[h.ItemTypeAttachment]
			i = getNewID(
				redirect.Origin.OriginID,
				redirect.ItemTypeID,
				atoi64(matches[1]),
			)
			if i == 0 {
				redirect.Status = http.StatusNotFound
				return redirect
			}
			redirect.ItemID = i
		}
	}

	// Random URLs
	if redirect.ItemTypeID == 0 && vbMemberList.MatchString(path) {
		redirect.ItemTypeID = h.ItemTypes[h.ItemTypeProfile]
	}

	if redirect.ItemTypeID == 0 && vbOnline.MatchString(path) {
		redirect.ItemTypeID = h.ItemTypes[h.ItemTypeProfile]
		redirect.Action = ActionWhoIsOnline
	}

	if redirect.ItemTypeID == 0 && vbPMs.MatchString(path) {
		redirect.ItemTypeID = h.ItemTypes[h.ItemTypeHuddle]
	}

	if redirect.ItemTypeID == 0 && vbSubscription.MatchString(path) {
		redirect.ItemTypeID = h.ItemTypes[h.ItemTypeUpdate]
	}

	if redirect.ItemTypeID == 0 && vbUserCP.MatchString(path) {
		redirect.ItemTypeID = h.ItemTypes[h.ItemTypeUpdate]
	}

	// Construct the actual URLs to send people to
	canPaginate := false
	switch redirect.ItemTypeID {
	case h.ItemTypes[h.ItemTypeMicrocosm]:
		redirect.ItemType = h.ItemTypeMicrocosm

		if redirect.ItemID > 0 {
			redirect.URL.Href = fmt.Sprintf(
				"%s/%d",
				h.APITypeMicrocosm,
				redirect.ItemID,
			)
		} else {
			redirect.URL.Href = h.APITypeMicrocosm
		}
		redirect.URL.Rel = redirect.ItemType
		canPaginate = true

	case h.ItemTypes[h.ItemTypeConversation]:
		redirect.ItemType = h.ItemTypeConversation

		switch redirect.Action {
		case ActionNewComment:
			if redirect.ItemID > 0 {

				t, _, err := models.GetLastReadTime(
					h.ItemTypes[h.ItemTypeConversation],
					redirect.ItemID,
					profileID,
				)
				if err != nil {
					redirect.Status = http.StatusNotFound
					return redirect
				}

				commentID, _, err := models.GetNextOrLastCommentID(
					h.ItemTypes[h.ItemTypeConversation],
					redirect.ItemID,
					t,
					profileID,
				)
				if err != nil {
					redirect.Status = http.StatusNotFound
					return redirect
				}

				redirect.ItemTypeID = h.ItemTypes[h.ItemTypeComment]
				redirect.ItemType = h.ItemTypeComment
				redirect.ItemID = commentID

				redirect.URL.Href = fmt.Sprintf(
					"%s/%d",
					h.APITypeComment,
					redirect.ItemID,
				)
				redirect.URL.Rel = redirect.ItemType
				redirect.Action = ActionCommentInContext

			} else {
				redirect.Status = http.StatusNotFound
				return redirect
			}
		default:
			if redirect.ItemID > 0 {
				redirect.URL.Href = fmt.Sprintf(
					"%s/%d",
					h.APITypeConversation,
					redirect.ItemID,
				)
				redirect.URL.Rel = redirect.ItemType
				canPaginate = true
			} else {
				redirect.Status = http.StatusNotFound
				return redirect
			}
		}

	case h.ItemTypes[h.ItemTypeComment]:
		redirect.ItemType = h.ItemTypeComment

		if redirect.ItemID > 0 {
			redirect.URL.Href = fmt.Sprintf(
				"%s/%d",
				h.APITypeComment,
				redirect.ItemID,
			)
			redirect.URL.Rel = redirect.ItemType
		} else {
			redirect.Status = http.StatusNotFound
			return redirect
		}

	case h.ItemTypes[h.ItemTypeAttachment]:
		redirect.ItemType = h.ItemTypeAttachment

		db, err := h.GetConnection()
		if err != nil {
			redirect.Status = http.StatusNotFound
			return redirect
		}

		var fileSha1 string
		err = db.QueryRow(`--Get Attachment ID
SELECT file_sha1
  FROM attachments
 WHERE attachment_meta_id = $1`,
			redirect.ItemID,
		).Scan(&fileSha1)
		if err != nil {
			redirect.Status = http.StatusNotFound
			return redirect
		}

		site, _, err := models.GetSite(redirect.Origin.SiteID)
		if err != nil {
			redirect.Status = http.StatusNotFound
			return redirect
		}

		redirect.URL.Href = fmt.Sprintf(
			"https://%s.microco.sm%s/%s",
			site.SubdomainKey,
			h.APITypeFile,
			fileSha1,
		)

	case h.ItemTypes[h.ItemTypeHuddle]:
		redirect.ItemType = h.ItemTypeHuddle

		if redirect.ItemID > 0 {
			redirect.URL.Href = fmt.Sprintf(
				"%s/%d",
				h.APITypeHuddle,
				redirect.ItemID,
			)
		} else {
			redirect.URL.Href = h.APITypeHuddle
		}
		redirect.URL.Rel = redirect.ItemType

	case h.ItemTypes[h.ItemTypeProfile]:
		redirect.ItemType = h.ItemTypeProfile

		if redirect.ItemID > 0 {
			redirect.URL.Href = fmt.Sprintf(
				"%s/%d",
				h.APITypeProfile,
				redirect.ItemID,
			)
		} else {
			switch redirect.Action {
			case ActionSearch:
				redirect.URL.Href = h.APITypeProfile + "?q=" + redirect.Search
			case ActionWhoIsOnline:
				redirect.URL.Href = h.APITypeProfile + "?online=true"
			default:
				redirect.URL.Href = h.APITypeProfile
			}
			canPaginate = true
		}
		redirect.URL.Rel = redirect.ItemType

	case h.ItemTypes[h.ItemTypeUpdate]:
		redirect.ItemType = h.ItemTypeUpdate
		redirect.URL.Href = h.APITypeUpdate
		redirect.URL.Rel = redirect.ItemType

	default:
		redirect.Status = http.StatusNotFound
		return redirect
	}

	// Append offset if applicable
	if canPaginate && redirect.Offset > 0 {
		url, err := url.Parse(redirect.URL.Href)
		if err != nil {
			redirect.Status = http.StatusNotFound
			return redirect
		}

		q := url.Query()
		q.Add("offset", strconv.FormatInt(redirect.Offset, 10))
		url.RawQuery = q.Encode()

		redirect.URL.Href = url.String()
	} else {
		redirect.Offset = 0
	}

	redirect.Status = http.StatusMovedPermanently

	return redirect
}