func (log *memLog) edit(e proto.EditMessageCommand) (*proto.Message, error) { log.Lock() defer log.Unlock() now := proto.Now() for _, msg := range log.msgs { if msg.ID == e.ID { if e.Parent != 0 { msg.Parent = e.Parent } if e.Content != "" { msg.Content = e.Content } if e.Delete { msg.Deleted = now } else { msg.Deleted = proto.Time{} } msg.Edited = now return maybeTruncate(msg), nil } } return nil, proto.ErrMessageNotFound }
func (rb *RoomBinding) EditMessage( ctx scope.Context, session proto.Session, edit proto.EditMessageCommand) ( proto.EditMessageReply, error) { var reply proto.EditMessageReply editID, err := snowflake.New() if err != nil { return reply, err } cols, err := allColumns(rb.DbMap, Message{}, "") if err != nil { return reply, err } t, err := rb.DbMap.Begin() if err != nil { return reply, err } rollback := func() { if err := t.Rollback(); err != nil { logging.Logger(ctx).Printf("rollback error: %s", err) } } var msg Message err = t.SelectOne(&msg, fmt.Sprintf("SELECT %s FROM message WHERE room = $1 AND id = $2", cols), rb.RoomName, edit.ID.String()) if err != nil { rollback() return reply, err } if msg.PreviousEditID.Valid && msg.PreviousEditID.String != edit.PreviousEditID.String() { rollback() return reply, proto.ErrEditInconsistent } entry := &MessageEditLog{ EditID: editID.String(), Room: rb.RoomName, MessageID: edit.ID.String(), PreviousEditID: msg.PreviousEditID, PreviousContent: msg.Content, PreviousParent: sql.NullString{ String: msg.Parent, Valid: true, }, } // TODO: tests pass in a nil session, until we add support for the edit command if session != nil { entry.EditorID = sql.NullString{ String: string(session.Identity().ID()), Valid: true, } } if err := t.Insert(entry); err != nil { rollback() return reply, err } now := time.Time(proto.Now()) sets := []string{"edited = $3", "previous_edit_id = $4"} args := []interface{}{rb.RoomName, edit.ID.String(), now, editID.String()} msg.Edited = gorp.NullTime{Valid: true, Time: now} if edit.Content != "" { args = append(args, edit.Content) sets = append(sets, fmt.Sprintf("content = $%d", len(args))) msg.Content = edit.Content } if edit.Parent != 0 { args = append(args, edit.Parent.String()) sets = append(sets, fmt.Sprintf("parent = $%d", len(args))) msg.Parent = edit.Parent.String() } if edit.Delete != msg.Deleted.Valid { if edit.Delete { args = append(args, now) sets = append(sets, fmt.Sprintf("deleted = $%d", len(args))) msg.Deleted = gorp.NullTime{Valid: true, Time: now} } else { sets = append(sets, "deleted = NULL") msg.Deleted.Valid = false } } query := fmt.Sprintf("UPDATE message SET %s WHERE room = $1 AND id = $2", strings.Join(sets, ", ")) if _, err := t.Exec(query, args...); err != nil { rollback() return reply, err } if edit.Announce { event := &proto.EditMessageEvent{ EditID: editID, Message: msg.ToTransmission(), } err = rb.broadcast(ctx, t, proto.EditMessageEventType, event, session) if err != nil { rollback() return reply, err } } if err := t.Commit(); err != nil { return reply, err } reply.EditID = editID reply.Message = msg.ToTransmission() return reply, nil }