func (a *A) allowsContent(op string) (bson.ObjectId, string, error) { uni := a.uni var typ string if op == "insert" { typ = uni.Req.Form["type"][0] // See TODO below. } else { content_id := patterns.ToIdWithCare(uni.Req.Form["id"][0]) // TODO: Don't let it panic if id does not exists, return descriptive error message. _typ, err := content_model.TypeOf(uni.Db, content_id) if err != nil { return "", "", err } typ = _typ } auth_opts, ignore := user.AuthOpts(uni, "content.types."+typ, op) if ignore { return "", "", fmt.Errorf("Auth options should not be ignored.") } err, _ := user.AuthAction(uni, auth_opts) if err != nil { return "", "", err } uid_i, has_uid := jsonp.Get(uni.Dat, "_user._id") if !has_uid { return "", "", fmt.Errorf("Can't %v content, you have no id.", op) } uid := uid_i.(bson.ObjectId) user_level := scut.Ulev(uni.Dat["_user"]) allowed_err := content_model.CanModifyContent(uni.Db, uni.Req.Form, 300, uid, user_level) if allowed_err != nil { return "", "", allowed_err } return uid, typ, nil }
// Return values: content type, general (fatal) error, puzzle error // Puzzle error is returned to support the decision of wether to put the comment into a moderation queue. func (a *A) allowsComment(op string) (string, error, error) { uni := a.uni inp := uni.Req.Form user_level := scut.Ulev(uni.Dat["_user"]) content_id := bson.ObjectIdHex(inp["content_id"][0]) typ, err := content_model.TypeOf(uni.Db, content_id) if err != nil { return "", err, nil } auth_opts, ignore := user.AuthOpts(uni, "content.types."+typ, op+"_comment") if ignore { return "", fmt.Errorf("Auth options should not be ignored."), nil } err, puzzle_err := user.AuthAction(uni, auth_opts) if err != nil { return "", err, nil } var user_id bson.ObjectId user_id_i, has := jsonp.Get(uni.Dat, "_user._id") // At this point the user will have a user id. TODO: except when the auth_opts is misconfigured. if !has { return "", fmt.Errorf("User has no id."), nil } if has { user_id = user_id_i.(bson.ObjectId) } if op != "insert" { err = content_model.CanModifyComment(uni.Db, inp, 300, user_id, user_level) // TODO: remove hard-coded value. } return typ, err, puzzle_err }
func (a *A) DeleteTag() error { uni := a.uni if scut.Ulev(uni.Dat["_user"]) < 300 { return fmt.Errorf("Only an admin can delete a tag.") } tag_id := uni.Req.Form["tag_id"][0] return content_model.DeleteTag(uni.Db, tag_id) }
// Immediately terminate the run of the action in case the user level is lower than the required level of the given action. // By default, if not otherwise specified, every action requires a level of 300 (admin rights). // // Made public to be able to call separately from PuzzlesSolved. // This way one can implement moderation. func UserAllowed(uni *context.Uni, auth_options map[string]interface{}) error { minlev := 300 lev_in_opt := auth_options["min_lev"] num, err := numcon.Int(lev_in_opt) if err == nil { minlev = num } if scut.Ulev(uni.Dat["_user"]) < minlev { return fmt.Errorf("You have no rights to do that.") } return nil }
// We never update drafts, they are immutable. func (a *A) saveDraft() error { uni := a.uni post := uni.Req.Form typ_s, has_typ := post["type"] if !has_typ { return fmt.Errorf("No type when saving draft.") } typ := typ_s[0] content_type_opt, has_opt := jsonp.GetM(uni.Opt, "Modules.content.types."+typ) if !has_opt { return fmt.Errorf("Can't find options of content type %v.", typ) } allows := content_model.AllowsDraft(content_type_opt, scut.Ulev(uni.Dat["_user"]), typ) if allows != nil { return allows } rules, has_rules := jsonp.GetM(uni.Opt, "Modules.content.types."+typ+".rules") if !has_rules { return fmt.Errorf("Can't find rules of content type %v.", typ) } draft_id, err := content_model.SaveDraft(uni.Db, rules, map[string][]string(post)) // Handle redirect. cont := map[string]interface{}{} if err == nil { // Go to the fresh draft if we succeeded to save it. cont["!type"] = typ + "_draft" cont["!id"] = draft_id.Hex() } else { // Go back to the previous draft if we couldn't save the new one, or to the insert page if we tried to save a parentless draft. draft_id, has_draft_id := uni.Req.Form[content_model.Parent_draft_field] if has_draft_id && len(draft_id[0]) > 0 { cont["!type"] = typ + "_draft" cont["!id"] = draft_id[0] } else if id, has_id := uni.Req.Form["id"]; has_id { cont["!type"] = typ cont["!id"] = id[0] } else { cont["!type"] = typ cont["!id"] = "" } } uni.Dat["_cont"] = cont return err }
// Similar to OkayToDoAction but it works directly on the auth_options map. func AuthAction(uni *context.Uni, auth_options map[string]interface{}) (error, error) { err := UserAllowed(uni, auth_options) if err != nil { return err, nil } user_level := scut.Ulev(uni.Dat["_user"]) no_puzzles_lev := numcon.IntP(auth_options["no_puzzles_lev"]) var hot_reg int if val, has := auth_options["hot_reg"]; has { hot_reg = numcon.IntP(val) } var puzzle_err error if user_level < no_puzzles_lev { puzzle_err = SolvePuzzles(uni, auth_options) } if user_level == 0 && ((puzzle_err == nil && hot_reg >= 1) || (puzzle_err != nil && hot_reg == 2)) { err = RegLoginBuild(uni, puzzle_err == nil) } return err, puzzle_err }