// 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"),
	)
}
示例#2
0
// 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()
}
示例#3
0
// Update handles PUT
func (ctl *EventController) Update(c *models.Context) {
	_, itemTypeID, itemID, status, err := c.GetItemTypeAndItemID()
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	// Validate inputs
	m, status, err := models.GetEvent(c.Site.ID, itemID, c.Auth.ProfileID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}
	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, itemTypeID, itemID),
	)
	if !perms.CanUpdate {
		c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
		return
	}
	// End Authorisation

	// Populate where applicable from auth and context
	m.Meta.EditedByNullable = sql.NullInt64{Int64: c.Auth.ProfileID, Valid: true}
	m.Meta.EditedNullable = pq.NullTime{Time: time.Now(), Valid: true}

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

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

	c.RespondWithSeeOther(
		fmt.Sprintf(
			"%s/%d",
			h.APITypeEvent,
			m.ID,
		),
	)
}
示例#4
0
// Update handles PUT
func (ctl *ProfileReadController) Update(c *models.Context) {
	if c.Auth.ProfileID == 0 {
		c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
		return
	}

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

	itemTypeID, ok := h.ItemTypes[rs.ItemType]
	if !ok {
		c.RespondWithErrorMessage("Unknown item type", http.StatusBadRequest)
		return
	}
	rs.ItemTypeID = itemTypeID

	status, err := models.MarkScopeAsRead(c.Auth.ProfileID, rs)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	c.RespondWithOK()
}
示例#5
0
// Update handles PUT
func (ctl *ProfileController) Update(c *models.Context) {
	_, itemTypeID, itemID, status, err := c.GetItemTypeAndItemID()
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	m, status, err := models.GetProfile(c.Site.ID, itemID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	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, itemTypeID, itemID),
	)
	if !perms.CanUpdate {
		c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
		return
	}
	// End Authorisation

	// Populate site and user ID from goweb context
	m.SiteID = c.Site.ID

	status, err = m.Update()
	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.RespondWithSeeOther(
		fmt.Sprintf(
			"%s/%d",
			h.APITypeProfile,
			m.ID,
		),
	)
}
示例#6
0
// Create handles POST
func (ctl *ProfilesController) Create(c *models.Context) {
	m := models.ProfileType{}
	m.Visible = true

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

	// TODO: Auth rules on creation

	if m.SiteID != 0 {
		c.RespondWithErrorMessage(
			"You cannot supply a site ID when creating a profile",
			http.StatusBadRequest,
		)
		return
	}

	if m.UserID != 0 {
		c.RespondWithErrorMessage(
			"You cannot supply a user ID when creating a profile",
			http.StatusBadRequest,
		)
		return
	}

	// Populate site and user ID from goweb context
	m.SiteID = c.Site.ID
	m.UserID = c.Auth.UserID

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

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

	c.RespondWithSeeOther(
		fmt.Sprintf(
			"%s/%d",
			h.APITypeProfile,
			m.ID,
		),
	)
}
示例#7
0
// Update handles PUT
func (ctl *AttributeController) Update(c *models.Context) {
	_, itemTypeID, itemID, status, err := c.GetItemTypeAndItemID()
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	key := c.RouteVars["key"]

	// Exception from normal model is that we don't attempt to fetch before
	// we update. We will be doing an upsert (update or insert) rather than
	// a pure update. As such, the item may not exist before we update it and
	// we allow that to be resolved later. This works in this case as the data
	// structure is simple and we don't care about extended metadata
	m := models.AttributeType{}
	m.Key = key
	m.Number = sql.NullFloat64{Float64: math.MaxFloat64}

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

	perms := models.GetPermission(models.MakeAuthorisationContext(c, 0, itemTypeID, itemID))
	if !perms.CanUpdate {
		c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
		return
	}

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

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

	c.RespondWithSeeOther(
		fmt.Sprintf(
			"%s/%s",
			fmt.Sprintf(h.APITypeAttribute, c.RouteVars["type"], itemID),
			key,
		),
	)
}
示例#8
0
// Update handles PUT
func (ctl *WatcherController) Update(c *models.Context) {
	m := models.WatcherType{}
	err := c.Fill(&m)

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

	itemType := strings.ToLower(m.ItemType)
	if itemType != "" {
		if _, exists := h.ItemTypes[itemType]; !exists {
			glog.Warning(err)
			c.RespondWithErrorMessage(
				fmt.Sprintf("Watcher could not be saved: Item type not found"),
				http.StatusBadRequest,
			)
			return
		}

		m.ItemTypeID = h.ItemTypes[itemType]
	}

	var status int
	// watcher must exist to be updated
	// Also the returned watcher ID belongs to the authed person by definition
	// - no need to check later
	m.ID, _, _, _, status, err = models.GetWatcherAndIgnoreStatus(
		m.ItemTypeID,
		m.ItemID,
		c.Auth.ProfileID,
	)
	if err != nil {
		glog.Error(err)
		c.RespondWithErrorDetail(err, status)
		return
	}

	// To update we only need id, SendEmail and SendSMS
	status, err = m.Update()
	if err != nil {
		glog.Error(err)
		c.RespondWithErrorMessage(
			fmt.Sprintf("Could not update watcher: %v", err.Error()),
			http.StatusBadRequest,
		)
		return
	}

	// Respond
	c.RespondWithOK()
}
示例#9
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))
}
// UpdateMany handles PUT for the collection
func (ctl *HuddleParticipantsController) UpdateMany(c *models.Context) {
	// Validate inputs
	huddleID, err := strconv.ParseInt(c.RouteVars["huddle_id"], 10, 64)
	if err != nil {
		c.RespondWithErrorMessage("huddle_id in URL is not a number", http.StatusBadRequest)
		return
	}

	r, status, err := models.GetHuddle(c.Site.ID, c.Auth.ProfileID, huddleID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	// Start Authorisation
	perms := models.GetPermission(
		models.MakeAuthorisationContext(
			c, 0, h.ItemTypes[h.ItemTypeHuddle], huddleID),
	)
	if !perms.CanUpdate {
		c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
		return
	}

	if r.IsConfidential == true {
		c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
		return
	}
	// End Authorisation

	ems := []models.HuddleParticipantType{}

	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.UpdateManyHuddleParticipants(c.Site.ID, huddleID, ems)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	c.RespondWithSeeOther(
		fmt.Sprintf(
			"%s/%d",
			h.APITypeHuddle,
			huddleID,
		),
	)
}
示例#11
0
// UpdateMany handles PUT for the collection
func (ctl *AttributesController) UpdateMany(c *models.Context) {
	_, itemTypeID, itemID, status, err := c.GetItemTypeAndItemID()
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	ems := []models.AttributeType{}

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

	for _, v := range ems {
		if strings.Trim(v.Key, " ") == "" {
			c.RespondWithErrorMessage(
				"key must be supplied with every attribute when updating multiple attributes",
				http.StatusBadRequest,
			)
			return
		}
	}

	perms := models.GetPermission(models.MakeAuthorisationContext(c, 0, itemTypeID, itemID))
	if !perms.CanUpdate {
		c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
		return
	}

	status, err = models.UpdateManyAttributes(itemTypeID, itemID, ems)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	for _, m := range ems {
		audit.Replace(
			c.Site.ID,
			h.ItemTypes[h.ItemTypeAttribute],
			m.ID,
			c.Auth.ProfileID,
			time.Now(),
			c.IP,
		)
	}

	c.RespondWithOK()
}
示例#12
0
// 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,
		),
	)
}
示例#13
0
// Update handles PUT
func (ctl *UpdateOptionController) Update(c *models.Context) {
	_, _, itemID, status, err := c.GetItemTypeAndItemID()
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	var exists bool

	m, status, err := models.GetUpdateOptionByUpdateType(c.Auth.ProfileID, itemID)
	if err != nil && status != http.StatusNotFound {
		c.RespondWithErrorDetail(err, status)
		return
	}
	if status == http.StatusOK {
		exists = true
	}

	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.UpdateTypeID = itemID
	m.ProfileID = c.Auth.ProfileID

	if exists {
		// Update
		status, err = m.Update()
	} else {
		// Create
		status, err = m.Insert()
	}
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	// Respond
	c.RespondWithSeeOther(
		fmt.Sprintf(
			h.APITypeUpdateOptionType,
			m.UpdateTypeID,
		),
	)
}
示例#14
0
// Create handles POST
func (ctl *WatchersController) Create(c *models.Context) {
	// Fill from POST data
	m := WatcherType{}
	err := c.Fill(&m)

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

	itemType := strings.ToLower(m.ItemType)
	if itemType != "" {
		if _, exists := h.ItemTypes[itemType]; !exists {
			c.RespondWithErrorMessage(
				fmt.Sprintf("Watcher could not be saved: Item type not found"),
				http.StatusBadRequest,
			)
			return
		}

		m.ItemTypeID = h.ItemTypes[itemType]
	} else {
		c.RespondWithErrorMessage(
			fmt.Sprintf("No itemType supplied, cannot create a watcher"),
			http.StatusBadRequest,
		)
		return
	}

	sendEmail, status, err := models.RegisterWatcher(
		c.Auth.ProfileID,
		m.UpdateTypeID,
		m.ItemID,
		m.ItemTypeID,
		c.Site.ID,
	)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("Watcher could not be registered: %v", err.Error()),
			status,
		)
		return
	}

	c.RespondWithData(sendEmail)
}
示例#15
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()
}
示例#16
0
// Update handles PUT
func (ctl *AttendeeController) Update(c *models.Context) {
	// Verify ID is a positive integer
	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
	}

	m := models.AttendeeType{}

	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.ItemTypeEvent], eventID),
	)
	if !perms.CanUpdate {
		c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
		return
	}

	if perms.IsOwner || perms.IsModerator || perms.IsSiteOwner {
		if m.ProfileID != c.Auth.ProfileID && m.RSVP == "yes" {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}
	} else {
		if m.ProfileID != c.Auth.ProfileID {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}
	}
	_, status, err := models.GetProfileSummary(c.Site.ID, m.ProfileID)
	if err != nil {
		c.RespondWithErrorMessage(h.NoAuthMessage, status)
		return
	}
	// End Authorisation

	// Populate where applicable from auth and context
	t := time.Now()
	m.EventID = eventID
	m.Meta.CreatedByID = c.Auth.ProfileID
	m.Meta.Created = t
	m.Meta.EditedByNullable = sql.NullInt64{Int64: c.Auth.ProfileID, Valid: true}
	m.Meta.EditedNullable = pq.NullTime{Time: t, Valid: true}

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

	if m.RSVP == "yes" {
		go models.SendUpdatesForNewAttendeeInAnEvent(c.Site.ID, m)
	}

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

	c.RespondWithSeeOther(
		fmt.Sprintf("%s/%d", fmt.Sprintf(h.APITypeAttendee, m.EventID), m.ProfileID),
	)
}
示例#17
0
// Create handles POST
func (ctl *AuthController) Create(c *models.Context) {
	accessTokenRequest := models.AccessTokenRequestType{}
	err := c.Fill(&accessTokenRequest)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("The post data is invalid: %v", err.Error()),
			http.StatusBadRequest,
		)
		return
	}

	// Audience is the host that Persona authenticates the user for
	var audience string
	if c.Site.Domain != "" {
		audience = c.Site.Domain
	} else if c.Site.SubdomainKey == "root" {
		audience = conf.ConfigStrings[conf.MicrocosmDomain]
	} else {
		audience = fmt.Sprintf("%s.%s", c.Site.SubdomainKey, conf.ConfigStrings[conf.MicrocosmDomain])
	}

	// Verify persona assertion
	personaRequest := models.PersonaRequestType{
		Assertion: accessTokenRequest.Assertion,
		Audience:  audience,
	}

	jsonData, err := json.Marshal(personaRequest)
	if err != nil {
		glog.Errorf("Could not marshal Persona req: %s", err.Error())
		c.RespondWithErrorMessage(
			fmt.Sprintf("Bad persona request format: %v", err.Error()),
			http.StatusBadRequest,
		)
		return
	}

	resp, err := http.Post(
		conf.ConfigStrings[conf.PersonaVerifierURL],
		"application/json",
		bytes.NewReader(jsonData),
	)
	if err != nil {
		glog.Errorln(err.Error())
		c.RespondWithErrorMessage(
			fmt.Sprintf("Persona verification error: %v", err.Error()),
			http.StatusInternalServerError,
		)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		glog.Errorf("Couldn't read Persona response: %s", err.Error())
		c.RespondWithErrorMessage(
			fmt.Sprintf("Error unmarshalling persona response: %v", err.Error()),
			http.StatusInternalServerError,
		)
		return
	}
	resp.Body.Close()
	var personaResponse = models.PersonaResponseType{}
	json.Unmarshal(body, &personaResponse)

	if personaResponse.Status != "okay" {
		// Split and decode the assertion to log the user's email address.
		var decoded bool
		if personaRequest.Assertion != "" {
			parts := strings.Split(personaRequest.Assertion, "~")
			moreParts := strings.Split(parts[0], ".")
			if len(moreParts) > 1 {
				data, err := base64.StdEncoding.DecodeString(moreParts[1] + "====")
				if err == nil {
					decoded = true
					glog.Errorf("Bad Persona response: %+v with decoded assertion: %+v", personaResponse, data)
				}
			}
		}
		if !decoded {
			glog.Errorf("Bad Persona response: %+v with assertion: %+v", personaResponse, personaRequest)
		}
		c.RespondWithErrorMessage(
			fmt.Sprintf("Persona login error: %v", personaResponse.Status),
			http.StatusInternalServerError,
		)
		return
	}

	if personaResponse.Email == "" {
		glog.Errorf("No persona email address")
		c.RespondWithErrorMessage(
			"Persona error: no email address received",
			http.StatusInternalServerError,
		)
		return
	}

	// Retrieve user details by email address
	user, status, err := models.GetUserByEmailAddress(personaResponse.Email)
	if status == http.StatusNotFound {
		// Check whether this email is a spammer before we attempt to create
		// an account
		if models.IsSpammer(personaResponse.Email) {
			glog.Errorf("Spammer: %s", personaResponse.Email)
			c.RespondWithErrorMessage("Spammer", http.StatusInternalServerError)
			return
		}

		user, status, err = models.CreateUserByEmailAddress(personaResponse.Email)
		if err != nil {
			c.RespondWithErrorMessage(
				fmt.Sprintf("Couldn't create user: %v", err.Error()),
				http.StatusInternalServerError,
			)
			return
		}
	} else if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("Error retrieving user: %v", err.Error()),
			http.StatusInternalServerError,
		)
		return
	}

	// Create a corresponding profile for this user
	profile, status, err := models.GetOrCreateProfile(c.Site, user)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("Failed to create profile with ID %d: %v", profile.ID, err.Error()),
			status,
		)
		return
	}

	// Fetch API client details by secret
	client, err := models.RetrieveClientBySecret(accessTokenRequest.ClientSecret)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("Error processing client secret: %v", err.Error()),
			http.StatusInternalServerError,
		)
		return
	}

	// Create and store access token
	tokenValue, err := h.RandString(128)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("Could not generate a random string: %v", err.Error()),
			http.StatusInternalServerError,
		)
		return
	}

	m := models.AccessTokenType{}
	m.TokenValue = tokenValue
	m.UserID = user.ID
	m.ClientID = client.ClientID

	status, err = m.Insert()
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("Could not create an access token: %v", err.Error()),
			status,
		)
		return
	}

	audit.Create(
		c.Site.ID,
		h.ItemTypes[h.ItemTypeAuth],
		profile.ID,
		profile.ID,
		time.Now(),
		c.IP,
	)

	c.RespondWithData(tokenValue)
}
示例#18
0
// Create handles POST
func (ctl *UsersController) Create(c *models.Context) {
	// Batch create users by email address
	ems := []models.UserType{}

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

	if !c.Auth.IsSiteOwner {
		c.RespondWithErrorMessage(
			"Only a site owner can batch create users",
			http.StatusForbidden,
		)
		return
	}

	for _, m := range ems {
		status, err := m.Validate(false)
		if err != nil {
			c.RespondWithErrorDetail(err, status)
			return
		}
	}

	// We are good to go
	profiles := []models.ProfileType{}

	for _, m := range ems {
		// Retrieve user details by email address
		user, status, err := models.GetUserByEmailAddress(m.Email)
		if status == http.StatusNotFound {

			user, status, err = models.CreateUserByEmailAddress(m.Email)
			if err != nil {
				c.RespondWithErrorMessage(
					fmt.Sprintf("Couldn't create user: %v", err.Error()),
					http.StatusInternalServerError,
				)
				return
			}

			audit.Create(
				c.Site.ID,
				h.ItemTypes[h.ItemTypeUser],
				user.ID,
				c.Auth.ProfileID,
				time.Now(),
				c.IP,
			)

		} else if err != nil {
			c.RespondWithErrorMessage(
				fmt.Sprintf("Error retrieving user: %v", err.Error()),
				http.StatusInternalServerError,
			)
			return
		}

		// create a corresponding profile for this user
		profile, status, err := models.GetOrCreateProfile(c.Site, user)
		if err != nil {
			c.RespondWithErrorMessage(
				fmt.Sprintf("Failed to create profile with ID %d: %v", profile.ID, err.Error()),
				status,
			)
			return
		}

		audit.Create(
			c.Site.ID,
			h.ItemTypes[h.ItemTypeProfile],
			profile.ID,
			c.Auth.ProfileID,
			time.Now(),
			c.IP,
		)

		profiles = append(profiles, profile)
	}

	c.RespondWithData(profiles)
}
示例#19
0
// Patch handles PATCH
func (ctl *RoleController) Patch(c *models.Context) {
	// Validate inputs
	var microcosmID int64
	if sid, exists := c.RouteVars["microcosm_id"]; exists {
		id, err := strconv.ParseInt(sid, 10, 64)
		if err != nil {
			c.RespondWithErrorMessage("microcosm_id in URL is not a number", http.StatusBadRequest)
			return
		}

		microcosmID = id
	}

	roleID, err := strconv.ParseInt(c.RouteVars["role_id"], 10, 64)
	if err != nil {
		c.RespondWithErrorMessage("microcosm_id in URL is not a number", http.StatusBadRequest)
		return
	}

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

	status, err := h.TestPatch(patches)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	// Start Authorisation
	ac := models.MakeAuthorisationContext(c, microcosmID, h.ItemTypes[h.ItemTypeMicrocosm], microcosmID)
	perms := models.GetPermission(ac)
	if microcosmID > 0 {
		// Related to a Microcosm
		if !perms.IsModerator && !c.Auth.IsSiteOwner {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}
	} else {
		// Default role for the site
		if !c.Auth.IsSiteOwner {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}
	}

	// All patches are 'replace'
	for _, patch := range patches {
		status, err := patch.ScanRawValue()
		if !patch.Bool.Valid {
			c.RespondWithErrorDetail(err, status)
			return
		}

		switch patch.Path {
		case "/moderator":
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/moderator requires a bool value", http.StatusBadRequest)
				return
			}
		case "/banned":
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/banned requires a bool value", http.StatusBadRequest)
				return
			}
		case "/read":
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/read requires a bool value", http.StatusBadRequest)
				return
			}
		case "/create":
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/create requires a bool value", http.StatusBadRequest)
				return
			}
		case "/update":
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/update requires a bool value", http.StatusBadRequest)
				return
			}
		case "/delete":
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/delete requires a bool value", http.StatusBadRequest)
				return
			}
		case "/closeOwn":
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/closeOwn requires a bool value", http.StatusBadRequest)
				return
			}
		case "/openOwn":
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/openOwn requires a bool value", http.StatusBadRequest)
				return
			}
		case "/readOthers":
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/readOthers requires a bool value", http.StatusBadRequest)
				return
			}
		default:
			c.RespondWithErrorMessage("Invalid patch operation path", http.StatusBadRequest)
			return
		}
	}
	// End Authorisation

	m, status, err := models.GetRole(c.Site.ID, microcosmID, roleID, c.Auth.ProfileID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

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

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

	c.RespondWithOK()
}
示例#20
0
// Create handles POST
func (ctl *AttachmentsController) Create(c *models.Context) {
	attachment := models.AttachmentType{}

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

	if attachment.FileHash == "" {
		c.RespondWithErrorMessage(
			"You must supply a file hash",
			http.StatusBadRequest,
		)
		return
	}

	// Check that the file hash has a corresponding attachment_meta record
	metadata, status, err := models.GetMetadata(attachment.FileHash)
	if err != nil {
		if status == http.StatusNotFound {
			c.RespondWithErrorMessage(
				fmt.Sprintf("File does not have a metadata record"),
				http.StatusBadRequest,
			)
			return
		}

		c.RespondWithErrorMessage(
			fmt.Sprintf("Could not retrieve metadata: %v", err.Error()),
			http.StatusBadRequest,
		)
		return
	}

	attachment.AttachmentMetaID = metadata.AttachmentMetaID

	// Determine whether this is an attachment to a profile or comment, and if the
	// user is authorised to do so
	pathPrefix := ""

	if c.RouteVars["profile_id"] != "" {
		profileID, err := strconv.ParseInt(c.RouteVars["profile_id"], 10, 64)
		if err != nil {
			c.RespondWithErrorMessage(
				fmt.Sprintf("The supplied profile ID ('%s') is not a number.", c.RouteVars["profile_id"]),
				http.StatusBadRequest,
			)
			return
		}
		_, status, err := models.GetProfileSummary(c.Site.ID, profileID)
		if err != nil {
			if status == http.StatusNotFound {
				c.RespondWithErrorMessage(
					fmt.Sprintf("Profile with ID ('%d') does not exist.", profileID),
					http.StatusBadRequest,
				)
				return
			}

			c.RespondWithErrorMessage(
				fmt.Sprintf("Could not retrieve profile: %v.", err.Error()),
				http.StatusInternalServerError,
			)
			return
		}

		perms := models.GetPermission(
			models.MakeAuthorisationContext(
				c, 0, h.ItemTypes[h.ItemTypeProfile], profileID),
		)
		if !perms.CanCreate && !perms.CanUpdate {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}

		attachment.ItemID = profileID
		attachment.ItemTypeID = h.ItemTypes[h.ItemTypeProfile]
		pathPrefix = h.APITypeProfile

	} else if c.RouteVars["comment_id"] != "" {
		commentID, err := strconv.ParseInt(c.RouteVars["comment_id"], 10, 64)
		if err != nil {
			c.RespondWithErrorMessage(
				fmt.Sprintf("The supplied comment ID ('%s') is not a number.", c.RouteVars["comment_id"]),
				http.StatusBadRequest,
			)
			return
		}

		_, status, err := models.GetCommentSummary(c.Site.ID, commentID)
		if err != nil {
			if status == http.StatusNotFound {
				c.RespondWithErrorMessage(
					fmt.Sprintf("Comment with ID ('%d') does not exist.", commentID),
					http.StatusBadRequest,
				)
				return
			}

			c.RespondWithErrorMessage(
				fmt.Sprintf("Could not retrieve comment: %v.", err.Error()),
				http.StatusInternalServerError,
			)
			return
		}

		perms := models.GetPermission(
			models.MakeAuthorisationContext(
				c, 0, h.ItemTypes[h.ItemTypeComment], commentID),
		)
		if !perms.CanCreate && !perms.CanUpdate {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}

		if metadata.FileSize > 3145728 {
			c.RespondWithErrorMessage(fmt.Sprintf("File size must be under 3 megabytes"), http.StatusBadRequest)
			return
		}

		attachment.ItemID = commentID
		attachment.ItemTypeID = h.ItemTypes[h.ItemTypeComment]
		pathPrefix = h.APITypeComment

	} else {
		c.RespondWithErrorMessage(
			"You must supply a profile_id or comment_id as a RouteVar",
			http.StatusBadRequest,
		)
		return
	}

	// Check that this file hasn't already been attached to this item
	oldattachment := models.AttachmentType{}
	oldattachment, status, err = models.GetAttachment(
		attachment.ItemTypeID,
		attachment.ItemID,
		attachment.FileHash,
		false,
	)

	if err != nil && status != http.StatusNotFound {
		c.RespondWithErrorMessage(
			fmt.Sprintf("An error occurred when checking the attachment: %v", err.Error()),
			http.StatusInternalServerError,
		)
		return
	}

	if status != http.StatusNotFound && attachment.ItemTypeID != h.ItemTypes[h.ItemTypeProfile] {
		c.RespondWithSeeOther(
			fmt.Sprintf("%s/%d/%s", pathPrefix, oldattachment.ItemID, h.APITypeAttachment),
		)
		return
	}

	if status == http.StatusNotFound {
		// Update attach count on attachment_meta
		metadata.AttachCount++
		status, err = metadata.Update()
		if err != nil {
			c.RespondWithErrorDetail(err, status)
			return
		}

		attachment.ProfileID = c.Auth.ProfileID
		attachment.Created = time.Now()

		status, err = attachment.Insert()
		if err != nil {
			c.RespondWithErrorDetail(err, status)
			return
		}
	} else {
		//already exists, need to update it and pull back the attachmentId
		attachment = oldattachment
		attachment.Created = time.Now()
		status, err = attachment.Update()
		if err != nil {
			c.RespondWithErrorDetail(err, status)
			return
		}
	}

	// If attaching to a profile, update the profile with new avatar URL
	if attachment.ItemTypeID == h.ItemTypes[h.ItemTypeProfile] {
		profile, _, err := models.GetProfile(c.Site.ID, attachment.ItemID)
		if err != nil {
			c.RespondWithErrorDetail(err, status)
			return
		}
		filePath := metadata.FileHash
		if metadata.FileExt != "" {
			filePath += `.` + metadata.FileExt
		}
		profile.AvatarURLNullable = sql.NullString{
			String: fmt.Sprintf("%s/%s", h.APITypeFile, filePath),
			Valid:  true,
		}
		profile.AvatarIDNullable = sql.NullInt64{
			Int64: attachment.AttachmentID,
			Valid: true,
		}
		status, err = profile.Update()
		if err != nil {
			c.RespondWithErrorMessage(
				fmt.Sprintf("Could not update profile with avatar: %v", err.Error()),
				status,
			)
			return
		}
	}

	c.RespondWithSeeOther(
		fmt.Sprintf("%s/%d/%s", pathPrefix, attachment.ItemID, h.APITypeAttachment),
	)
}
示例#21
0
// UpdateMany handles PUT on the collection
func (ctl *AttendeesController) UpdateMany(c *models.Context) {
	// Verify event_id is a positive integer
	eventID, err := strconv.ParseInt(c.RouteVars["event_id"], 10, 64)
	if err != nil {
		glog.Errorln(err.Error())
		c.RespondWithErrorMessage(
			fmt.Sprintf("The supplied event ID ('%s') is not a number.", c.RouteVars["event_id"]),
			http.StatusBadRequest,
		)
		return
	}

	ems := []models.AttendeeType{}

	err = c.Fill(&ems)
	if err != nil {
		glog.Errorln(err.Error())
		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.ItemTypeEvent], eventID),
	)

	if !perms.CanCreate {
		c.RespondWithErrorDetail(
			e.New(c.Site.ID, c.Auth.ProfileID, "attendees.go::UpdateMany", e.NoCreate, "Not authorized to create attendee: CanCreate false"),
			http.StatusForbidden,
		)
		return
	}
	// Everyone can set self to any status.  Event/site owners can set people to any status apart from 'attending'.
	// Also check that profile exists on site.
	if perms.IsOwner || perms.IsModerator || perms.IsSiteOwner {
		for _, m := range ems {
			if m.ProfileID != c.Auth.ProfileID && m.RSVP == "yes" {
				c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
				return
			}
			_, status, err := models.GetProfileSummary(c.Site.ID, m.ProfileID)
			if err != nil {
				c.RespondWithErrorMessage(h.NoAuthMessage, status)
				return
			}
		}
	} else {
		for _, m := range ems {
			if m.ProfileID != c.Auth.ProfileID {
				c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
				return
			}
			_, status, err := models.GetProfileSummary(c.Site.ID, m.ProfileID)
			if err != nil {
				c.RespondWithErrorMessage(h.NoAuthMessage, status)
				return
			}
		}
	}
	// End : Authorisation

	t := time.Now()
	// Populate where applicable from auth and context
	for i := range ems {
		ems[i].EventID = eventID
		ems[i].Meta.CreatedByID = c.Auth.ProfileID
		ems[i].Meta.Created = t
		ems[i].Meta.EditedNullable = pq.NullTime{Time: t, Valid: true}
		ems[i].Meta.EditedByNullable = sql.NullInt64{Int64: c.Auth.ProfileID, Valid: true}
	}

	status, err := models.UpdateManyAttendees(c.Site.ID, ems)
	if err != nil {
		glog.Error(err)
		c.RespondWithErrorDetail(err, status)
		return
	}
	for _, m := range ems {
		if m.RSVP == "yes" {
			go models.SendUpdatesForNewAttendeeInAnEvent(c.Site.ID, m)

			// The new attendee should be following the event now
			go models.RegisterWatcher(
				m.ProfileID,
				h.UpdateTypes[h.UpdateTypeEventReminder],
				m.EventID,
				h.ItemTypes[h.ItemTypeEvent],
				c.Site.ID,
			)
		}

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

	c.RespondWithOK()
}
示例#22
0
// DeleteMany handles DELETE
// Removes one or more profiles (that were explicitly assigned) from this role
func (ctl *RoleProfilesController) DeleteMany(c *models.Context) {
	// Validate inputs
	var microcosmID int64
	if sid, exists := c.RouteVars["microcosm_id"]; exists {
		id, err := strconv.ParseInt(sid, 10, 64)
		if err != nil {
			c.RespondWithErrorMessage("microcosm_id in URL is not a number", http.StatusBadRequest)
			return
		}

		microcosmID = id
	}

	roleID, err := strconv.ParseInt(c.RouteVars["role_id"], 10, 64)
	if err != nil {
		c.RespondWithErrorMessage("role_id in URL is not a number", http.StatusBadRequest)
		return
	}

	_, status, err := models.GetRole(c.Site.ID, microcosmID, roleID, c.Auth.ProfileID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	ems := []models.RoleProfileType{}

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

	// Authorisation
	perms := models.GetPermission(
		models.MakeAuthorisationContext(c, microcosmID, h.ItemTypes[h.ItemTypeMicrocosm], microcosmID),
	)
	if microcosmID > 0 {
		// Related to a Microcosm
		if !perms.IsModerator && !c.Auth.IsSiteOwner {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}
	} else {
		// Default role for the site
		if !c.Auth.IsSiteOwner {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}
	}

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

	c.RespondWithOK()
}
示例#23
0
// Create handles POST
func (ctl *CommentsController) Create(c *models.Context) {
	m := models.CommentSummaryType{}
	err := c.Fill(&m)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("The post data is invalid: %v", err.Error()),
			http.StatusBadRequest,
		)
		return
	}

	// Populate where applicable from auth and context
	m.Meta.CreatedByID = c.Auth.ProfileID
	m.Meta.Created = time.Now()

	status, err := m.Validate(c.Site.ID, false)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	// Start : Authorisation
	perms := models.GetPermission(
		models.MakeAuthorisationContext(
			c, 0, m.ItemTypeID, m.ItemID),
	)
	if !perms.CanCreate {
		c.RespondWithErrorDetail(
			e.New(
				c.Site.ID,
				c.Auth.ProfileID,
				"comments.go::Create",
				e.NoCreate,
				"Not authorized to create comment: CanCreate false",
			),
			http.StatusForbidden,
		)
		return
	}
	// End : Authorisation

	// Create
	status, err = m.Insert(c.Site.ID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	go audit.Create(
		c.Site.ID,
		h.ItemTypes[h.ItemTypeComment],
		m.ID,
		c.Auth.ProfileID,
		time.Now(),
		c.IP,
	)

	// Send updates and register watcher
	if m.ItemTypeID == h.ItemTypes[h.ItemTypeHuddle] {
		models.RegisterWatcher(
			c.Auth.ProfileID,
			h.UpdateTypes[h.UpdateTypeNewCommentInHuddle],
			m.ItemID,
			m.ItemTypeID,
			c.Site.ID,
		)

		go models.SendUpdatesForNewCommentInHuddle(c.Site.ID, m)
		models.MarkAsRead(h.ItemTypes[h.ItemTypeHuddle], m.ItemID, c.Auth.ProfileID, time.Now())
		models.UpdateUnreadHuddleCount(c.Auth.ProfileID)
	} else {
		models.RegisterWatcher(
			c.Auth.ProfileID,
			h.UpdateTypes[h.UpdateTypeNewComment],
			m.ItemID,
			m.ItemTypeID,
			c.Site.ID,
		)

		go models.SendUpdatesForNewCommentInItem(c.Site.ID, m)
	}

	if m.InReplyTo > 0 {
		go models.SendUpdatesForNewReplyToYourComment(c.Site.ID, m)
	}

	// Respond
	c.RespondWithSeeOther(
		fmt.Sprintf(
			"%s/%d",
			h.APITypeComment,
			m.ID,
		),
	)
}
示例#24
0
// Update handles PUT
func (ctl *RoleController) Update(c *models.Context) {
	// Validate inputs
	var microcosmID int64
	if sid, exists := c.RouteVars["microcosm_id"]; exists {
		id, err := strconv.ParseInt(sid, 10, 64)
		if err != nil {
			c.RespondWithErrorMessage("microcosm_id in URL is not a number", http.StatusBadRequest)
			return
		}

		microcosmID = id
	}

	roleID, err := strconv.ParseInt(c.RouteVars["role_id"], 10, 64)
	if err != nil {
		c.RespondWithErrorMessage("microcosm_id in URL is not a number", http.StatusBadRequest)
		return
	}

	m, status, err := models.GetRole(c.Site.ID, microcosmID, roleID, c.Auth.ProfileID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

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

	// Authorisation
	perms := models.GetPermission(
		models.MakeAuthorisationContext(c, microcosmID, h.ItemTypes[h.ItemTypeMicrocosm], microcosmID),
	)
	if microcosmID > 0 {
		// Related to a Microcosm
		if !perms.IsModerator && !c.Auth.IsSiteOwner {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}
	} else {
		// Default role for the site
		if !c.Auth.IsSiteOwner {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}
	}

	// Populate where applicable from auth and context
	m.Meta.EditedByNullable = sql.NullInt64{Int64: c.Auth.ProfileID, Valid: true}
	m.Meta.EditedNullable = pq.NullTime{Time: time.Now(), Valid: true}

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

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

	c.RespondWithSeeOther(m.GetLink())
}
示例#25
0
// Patch handles PATCH
func (ctl *EventController) Patch(c *models.Context) {
	_, itemTypeID, itemID, status, err := c.GetItemTypeAndItemID()
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

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

	status, err = h.TestPatch(patches)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

	// Start Authorisation
	ac := models.MakeAuthorisationContext(c, 0, itemTypeID, itemID)
	perms := models.GetPermission(ac)
	if !perms.CanUpdate {
		c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
		return
	}

	// All patches are 'replace'
	for _, patch := range patches {
		status, err := patch.ScanRawValue()
		if !patch.Bool.Valid {
			c.RespondWithErrorDetail(err, status)
			return
		}

		switch patch.Path {
		case "/meta/flags/sticky":
			// Only super users' can sticky and unsticky
			if !perms.IsModerator {
				c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
				return
			}
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/meta/flags/sticky requires a bool value", http.StatusBadRequest)
				return
			}
		case "/meta/flags/open":
			// Only super users' and item owners can open and close
			if !(perms.IsModerator || perms.IsOwner) {
				c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
				return
			}
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/meta/flags/open requires a bool value", http.StatusBadRequest)
				return
			}
		case "/meta/flags/deleted":
			// Only super users' can undelete, but super users' and owners can delete
			if !patch.Bool.Valid {
				c.RespondWithErrorMessage("/meta/flags/deleted requires a bool value", http.StatusBadRequest)
				return
			}
			if (patch.Bool.Bool == false && !(perms.IsModerator || perms.IsOwner)) || !perms.IsModerator {
				c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
				return
			}
		case "/meta/flags/moderated":
			if !perms.IsModerator {
				c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
				return
			}
		default:
			c.RespondWithErrorMessage("Invalid patch operation path", http.StatusBadRequest)
			return
		}
	}
	// End Authorisation

	m, status, err := models.GetEvent(c.Site.ID, itemID, c.Auth.ProfileID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

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

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

	c.RespondWithOK()
}
示例#26
0
// Create handles POST
// If microcosm_id is provided in request args then this is a role on a microcosm
// otherwise this is a default role on this site
func (ctl *RolesController) Create(c *models.Context) {

	var microcosmID int64
	if sid, exists := c.RouteVars["microcosm_id"]; exists {
		id, err := strconv.ParseInt(sid, 10, 64)
		if err != nil {
			c.RespondWithErrorMessage("microcosm_id in URL is not a number", http.StatusBadRequest)
			return
		}

		microcosmID = id
	}

	// Validate inputs
	m := models.RoleType{}
	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, microcosmID, h.ItemTypes[h.ItemTypeMicrocosm], microcosmID),
	)
	if microcosmID > 0 {
		// Related to a Microcosm
		if !perms.IsModerator && !c.Auth.IsSiteOwner {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}
	} else {
		// Default role for the site
		if !c.Auth.IsSiteOwner {
			c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
			return
		}
	}
	// End : Authorisation

	// Populate where applicable from auth and context
	m.SiteID = c.Site.ID
	m.MicrocosmID = microcosmID
	m.Meta.CreatedByID = c.Auth.ProfileID
	m.Meta.Created = time.Now()

	status, err := m.Insert(c.Site.ID, c.Auth.ProfileID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

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

	c.RespondWithSeeOther(m.GetLink())
}
示例#27
0
// Create handles POST
func (ctl *EventsController) Create(c *models.Context) {
	m := models.EventType{}
	m.Meta.Flags.Open = true

	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.ItemTypeMicrocosm], m.MicrocosmID),
	)
	if !perms.CanCreate {
		c.RespondWithErrorMessage(h.NoAuthMessage, http.StatusForbidden)
		return
	}
	// End : Authorisation

	// Populate where applicable from auth and context
	m.Meta.CreatedByID = c.Auth.ProfileID
	m.Meta.Created = time.Now()

	status, err := m.Insert(c.Site.ID, c.Auth.ProfileID)
	if err != nil {
		c.RespondWithErrorDetail(err, status)
		return
	}

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

	go models.SendUpdatesForNewItemInAMicrocosm(c.Site.ID, m)

	go models.RegisterWatcher(
		c.Auth.ProfileID,
		h.UpdateTypes[h.UpdateTypeNewComment],
		m.ID,
		h.ItemTypes[h.ItemTypeEvent],
		c.Site.ID,
	)

	c.RespondWithSeeOther(
		fmt.Sprintf(
			"%s/%d",
			h.APITypeEvent,
			m.ID,
		),
	)
}
示例#28
0
// Create handles POST
func (ctl *SitesController) Create(c *models.Context) {
	if c.Auth.ProfileID < 1 {
		c.RespondWithErrorMessage(
			fmt.Sprintf("You must be logged in to the root site create a site"),
			http.StatusForbidden,
		)
		return
	}

	if c.Site.ID != 1 {
		c.RespondWithErrorMessage(
			fmt.Sprintf("Sites can only be created from the root site"),
			http.StatusBadRequest,
		)
		return
	}

	bytes, _ := httputil.DumpRequest(c.Request, true)
	glog.Infoln(string(bytes))

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

	// Fetch full user info from context user ID
	user, status, err := models.GetUser(c.Auth.UserID)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("Could not retrieve use associated with ID %d", c.Auth.UserID),
			status,
		)
		return
	}

	site, _, status, err := models.CreateOwnedSite(m, user)
	if err != nil {
		c.RespondWithErrorMessage(
			fmt.Sprintf("Error creating site: %s", err.Error()),
			http.StatusInternalServerError,
		)
		return
	}

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

	c.RespondWithSeeOther(fmt.Sprintf("%s/%d", h.APITypeSite, site.ID))
}