func (m *MessagesController) createSingle(ctx *gin.Context, messageIn *tat.MessageJSON) (*tat.MessageJSONOut, int, error) { msg, topic, user, e := m.preCheckTopic(ctx, messageIn) if e != nil { return nil, http.StatusInternalServerError, fmt.Errorf("No RW Access to topic %s", messageIn.Topic) } if isRw, _ := topicDB.GetUserRights(&topic, user); !isRw { return nil, http.StatusForbidden, fmt.Errorf("No RW Access to topic %s", messageIn.Topic) } var message = tat.Message{} idRef := "" if msg.ID != "" { idRef = msg.ID } text := messageIn.Text if idRef != "" && messageIn.Text != "" && (len(messageIn.Replies) > 0 || len(messageIn.Messages) > 0) { text = "" } // New root message or reply err := messageDB.Insert(&message, *user, topic, text, idRef, messageIn.DateCreation, messageIn.Labels, messageIn.Replies, messageIn.Messages, false, nil) if err != nil { log.Errorf("%s", err.Error()) return nil, http.StatusInternalServerError, err } info := fmt.Sprintf("Message created in %s", topic.Topic) out := &tat.MessageJSONOut{Message: message, Info: info} hook.SendHook(&tat.HookJSON{HookMessage: &tat.HookMessageJSON{MessageJSONOut: out, Action: tat.MessageActionCreate}}, topic) return out, http.StatusCreated, nil }
func (t *TopicsController) innerOneTopic(ctx *gin.Context, topicRequest string) (*tat.TopicJSON, *tat.User, int, error) { var user = tat.User{} found, err := userDB.FindByUsername(&user, getCtxUsername(ctx)) if !found { return nil, nil, http.StatusInternalServerError, fmt.Errorf("User unknown") } else if err != nil { return nil, nil, http.StatusInternalServerError, fmt.Errorf("Error while fetching user.") } topic, errfind := topicDB.FindByTopic(topicRequest, user.IsAdmin, true, true, &user) if errfind != nil { topic, _, err = checkDMTopic(ctx, topicRequest) if err != nil { return nil, nil, http.StatusBadRequest, fmt.Errorf("topic " + topicRequest + " does not exist or you have no access on it") } } filters := []tat.Filter{} for _, f := range topic.Filters { if f.UserID == user.ID { filters = append(filters, f) } } topic.Filters = filters out := &tat.TopicJSON{Topic: topic} out.IsTopicRw, out.IsTopicAdmin = topicDB.GetUserRights(topic, &user) return out, &user, http.StatusOK, nil }
func (m *MessagesController) innerList(ctx *gin.Context) (*tat.MessagesJSON, tat.User, tat.Topic, *tat.MessageCriteria, int, error) { var criteria = m.buildCriteria(ctx) if criteria.Limit <= 0 || criteria.Limit > 1000 { return nil, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, fmt.Errorf("Please put a limit <= 50 for fetching message") } log.Debugf("criteria::---> %+v", criteria) out := &tat.MessagesJSON{} // we can't use NotLabel or NotTag with fulltree or onetree // this avoid potential wrong results associated with a short param limit if (criteria.NotLabel != "" || criteria.NotTag != "") && (criteria.TreeView == tat.TreeViewFullTree || criteria.TreeView == tat.TreeViewOneTree) && criteria.OnlyMsgRoot == "" { return out, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, fmt.Errorf("You can't use fulltree or onetree with NotLabel or NotTag") } topicIn, err := GetParam(ctx, "topic") if err != nil { return out, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, fmt.Errorf("Invalid topic") } criteria.Topic = topicIn // add / if search on topic // as topic is in path, it can't start with a / if criteria.Topic != "" && string(criteria.Topic[0]) != "/" { criteria.Topic = "/" + criteria.Topic } var user tat.User var e error if getCtxUsername(ctx) != "" { user, e = PreCheckUser(ctx) if e != nil { return out, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, e } } topic, errt := topicDB.FindByTopic(criteria.Topic, true, false, false, &user) if errt != nil { topicCriteria := "" _, topicCriteria, err = checkDMTopic(ctx, criteria.Topic) if err != nil { return out, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, fmt.Errorf("topic " + criteria.Topic + " does not exist or you have no read access on it") } // hack to get new created DM Topic topic, errt = topicDB.FindByTopic(topicCriteria, true, false, false, &user) if errt != nil { return out, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, fmt.Errorf("topic " + criteria.Topic + " does not exist or you have no read access on it (2)") } criteria.Topic = topicCriteria } out.IsTopicRw, out.IsTopicAdmin = topicDB.GetUserRights(topic, &user) return out, user, *topic, criteria, -1, nil }
// Update a message : like, unlike, add label, etc... func (m *MessagesController) Update(ctx *gin.Context) { messageIn := &tat.MessageJSON{} ctx.Bind(messageIn) messageReference, topic, user, e := m.preCheckTopic(ctx, messageIn) if e != nil { return } if messageIn.Action == "like" || messageIn.Action == "unlike" { m.likeOrUnlike(ctx, messageIn.Action, messageReference, topic, *user) return } isRW, isAdminOnTopic := topicDB.GetUserRights(&topic, user) if !isRW { ctx.AbortWithError(http.StatusForbidden, errors.New("No RW Access to topic : "+messageIn.Topic)) return } if messageIn.Action == tat.MessageActionLabel || messageIn.Action == tat.MessageActionUnlabel || messageIn.Action == tat.MessageActionRelabel { m.addOrRemoveLabel(ctx, messageIn, messageReference, *user, topic) return } if messageIn.Action == tat.MessageActionVoteup || messageIn.Action == tat.MessageActionVotedown || messageIn.Action == tat.MessageActionUnvoteup || messageIn.Action == tat.MessageActionUnvotedown { m.voteMessage(ctx, messageIn, messageReference, *user, topic) return } if messageIn.Action == tat.MessageActionTask || messageIn.Action == tat.MessageActionUntask { m.addOrRemoveTask(ctx, messageIn, messageReference, *user, topic) return } if messageIn.Action == tat.MessageActionUpdate || messageIn.Action == tat.MessageActionConcat { m.updateMessage(ctx, messageIn, messageReference, *user, topic, isAdminOnTopic) return } if messageIn.Action == tat.MessageActionMove { // topic here is fromTopic m.moveMessage(ctx, messageIn, messageReference, *user, topic) return } ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Action"}) }
func (m *MessagesController) moveMessage(ctx *gin.Context, messageIn *tat.MessageJSON, message tat.Message, user tat.User, fromTopic tat.Topic) { // Check if user can delete msg on from topic if err := m.checkBeforeDelete(ctx, message, user, true, fromTopic); err != nil { // ctx writes in checkBeforeDelete return } toTopic, err := topicDB.FindByTopic(messageIn.Option, true, false, false, &user) if err != nil { e := fmt.Sprintf("Topic destination %s does not exist", message.Topic) ctx.JSON(http.StatusNotFound, gin.H{"error": e}) return } // Check if user can write msg from dest topic if isRW, _ := topicDB.GetUserRights(toTopic, &user); !isRW { ctx.JSON(http.StatusForbidden, gin.H{"error": fmt.Sprintf("No RW Access to topic %s", toTopic.Topic)}) return } // check if message is a reply -> not possible if message.InReplyOfIDRoot != "" { ctx.JSON(http.StatusForbidden, gin.H{"error": fmt.Sprintf("You can't move a reply message")}) return } info := "" if messageIn.Action == tat.MessageActionMove { err := messageDB.Move(&message, user, fromTopic, *toTopic) if err != nil { log.Errorf("Error while move a message to topic: %s err: %s", toTopic.Topic, err) ctx.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Error while move a message to topic %s", toTopic.Topic)}) return } info = fmt.Sprintf("Message move to %s", toTopic.Topic) } else { ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid action: " + messageIn.Action}) return } out := &tat.MessageJSONOut{Info: info, Message: message} hook.SendHook(&tat.HookJSON{HookMessage: &tat.HookMessageJSON{MessageJSONOut: out, Action: messageIn.Action}}, *toTopic) ctx.JSON(http.StatusCreated, out) }
// checkBeforeDelete checks // - if user is RW on topic // - if topic is Private OR is CanDeleteMsg or CanDeleteAllMsg func (m *MessagesController) checkBeforeDelete(ctx *gin.Context, message tat.Message, user tat.User, force bool, topic tat.Topic) error { isRW, isTopicAdmin := topicDB.GetUserRights(&topic, &user) if !isRW { e := fmt.Sprintf("No RW Access to topic %s", message.Topic) ctx.JSON(http.StatusForbidden, gin.H{"error": e}) return fmt.Errorf(e) } if topic.AdminCanDeleteAllMsg && isTopicAdmin { return nil } if !strings.HasPrefix(message.Topic, "/Private/"+user.Username) && !topic.CanDeleteMsg && !topic.CanDeleteAllMsg { if !topic.CanDeleteMsg && !topic.CanDeleteAllMsg { e := fmt.Sprintf("You can't delete a message from topic %s", topic.Topic) ctx.JSON(http.StatusForbidden, gin.H{"error": e}) return fmt.Errorf(e) } e := fmt.Sprintf("Could not delete a message in topic %s", message.Topic) ctx.JSON(http.StatusBadRequest, gin.H{"error": e}) return fmt.Errorf(e) } if !topic.CanDeleteAllMsg && message.Author.Username != user.Username && !strings.HasPrefix(message.Topic, "/Private/"+user.Username) { // if it's a reply and force true, allow delete it. if !force || (force && message.InReplyOfIDRoot == "") { e := fmt.Sprintf("Could not delete a message from another user %s than you %s", message.Author.Username, user.Username) ctx.JSON(http.StatusBadRequest, gin.H{"error": e}) return fmt.Errorf(e) } } // if label done on msg, can delete it if !force && message.IsDoing() { e := fmt.Sprintf("Could not delete a message with a doing label") ctx.JSON(http.StatusBadRequest, gin.H{"error": e}) return fmt.Errorf(e) } return nil }