188 lines
4.3 KiB
Go
188 lines
4.3 KiB
Go
|
package arn
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"reflect"
|
||
|
|
||
|
"github.com/aerogo/aero"
|
||
|
"github.com/aerogo/api"
|
||
|
"github.com/aerogo/markdown"
|
||
|
"github.com/animenotifier/notify.moe/arn/autocorrect"
|
||
|
)
|
||
|
|
||
|
// Force interface implementations
|
||
|
var (
|
||
|
_ Postable = (*Thread)(nil)
|
||
|
_ Likeable = (*Thread)(nil)
|
||
|
_ LikeEventReceiver = (*Thread)(nil)
|
||
|
_ Lockable = (*Thread)(nil)
|
||
|
_ LockEventReceiver = (*Thread)(nil)
|
||
|
_ PostParent = (*Thread)(nil)
|
||
|
_ fmt.Stringer = (*Thread)(nil)
|
||
|
_ api.Newable = (*Thread)(nil)
|
||
|
_ api.Editable = (*Thread)(nil)
|
||
|
_ api.Actionable = (*Thread)(nil)
|
||
|
_ api.Deletable = (*Thread)(nil)
|
||
|
)
|
||
|
|
||
|
// Actions
|
||
|
func init() {
|
||
|
API.RegisterActions("Thread", []*api.Action{
|
||
|
// Like thread
|
||
|
LikeAction(),
|
||
|
|
||
|
// Unlike thread
|
||
|
UnlikeAction(),
|
||
|
|
||
|
// Lock thread
|
||
|
LockAction(),
|
||
|
|
||
|
// Unlock thread
|
||
|
UnlockAction(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Authorize returns an error if the given API POST request is not authorized.
|
||
|
func (thread *Thread) Authorize(ctx aero.Context, action string) error {
|
||
|
if !ctx.HasSession() {
|
||
|
return errors.New("Neither logged in nor in session")
|
||
|
}
|
||
|
|
||
|
if action == "edit" {
|
||
|
user := GetUserFromContext(ctx)
|
||
|
|
||
|
if thread.CreatedBy != user.ID && user.Role != "admin" {
|
||
|
return errors.New("Can't edit the threads of other users")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Create sets the data for a new thread with data we received from the API request.
|
||
|
func (thread *Thread) Create(ctx aero.Context) error {
|
||
|
data, err := ctx.Request().Body().JSONObject()
|
||
|
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
userID, ok := ctx.Session().Get("userId").(string)
|
||
|
|
||
|
if !ok || userID == "" {
|
||
|
return errors.New("Not logged in")
|
||
|
}
|
||
|
|
||
|
user, err := GetUser(userID)
|
||
|
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
thread.ID = GenerateID("Thread")
|
||
|
thread.Title, _ = data["title"].(string)
|
||
|
thread.Text, _ = data["text"].(string)
|
||
|
thread.CreatedBy = user.ID
|
||
|
thread.Sticky, _ = data["sticky"].(int)
|
||
|
thread.Created = DateTimeUTC()
|
||
|
thread.Edited = ""
|
||
|
|
||
|
// Post-process text
|
||
|
thread.Title = autocorrect.ThreadTitle(thread.Title)
|
||
|
thread.Text = autocorrect.PostText(thread.Text)
|
||
|
|
||
|
// Tags
|
||
|
tags, _ := data["tags"].([]interface{})
|
||
|
thread.Tags = make([]string, len(tags))
|
||
|
|
||
|
for i := range thread.Tags {
|
||
|
thread.Tags[i] = tags[i].(string)
|
||
|
}
|
||
|
|
||
|
if len(tags) < 1 {
|
||
|
return errors.New("Need to specify at least one tag")
|
||
|
}
|
||
|
|
||
|
if len(thread.Title) < 10 {
|
||
|
return errors.New("Title too short: Should be at least 10 characters")
|
||
|
}
|
||
|
|
||
|
if len(thread.Text) < 10 {
|
||
|
return errors.New("Text too short: Should be at least 10 characters")
|
||
|
}
|
||
|
|
||
|
// Write log entry
|
||
|
logEntry := NewEditLogEntry(user.ID, "create", "Thread", thread.ID, "", "", "")
|
||
|
logEntry.Save()
|
||
|
|
||
|
// Create activity
|
||
|
activity := NewActivityCreate("Thread", thread.ID, user.ID)
|
||
|
activity.Save()
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Edit creates an edit log entry.
|
||
|
func (thread *Thread) Edit(ctx aero.Context, key string, value reflect.Value, newValue reflect.Value) (consumed bool, err error) {
|
||
|
return edit(thread, ctx, key, value, newValue)
|
||
|
}
|
||
|
|
||
|
// OnAppend saves a log entry.
|
||
|
func (thread *Thread) OnAppend(ctx aero.Context, key string, index int, obj interface{}) {
|
||
|
onAppend(thread, ctx, key, index, obj)
|
||
|
}
|
||
|
|
||
|
// OnRemove saves a log entry.
|
||
|
func (thread *Thread) OnRemove(ctx aero.Context, key string, index int, obj interface{}) {
|
||
|
onRemove(thread, ctx, key, index, obj)
|
||
|
}
|
||
|
|
||
|
// AfterEdit sets the edited date on the thread object.
|
||
|
func (thread *Thread) AfterEdit(ctx aero.Context) error {
|
||
|
thread.Edited = DateTimeUTC()
|
||
|
thread.html = markdown.Render(thread.Text)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Save saves the thread object in the database.
|
||
|
func (thread *Thread) Save() {
|
||
|
DB.Set("Thread", thread.ID, thread)
|
||
|
}
|
||
|
|
||
|
// DeleteInContext deletes the thread in the given context.
|
||
|
func (thread *Thread) DeleteInContext(ctx aero.Context) error {
|
||
|
user := GetUserFromContext(ctx)
|
||
|
|
||
|
// Write log entry
|
||
|
logEntry := NewEditLogEntry(user.ID, "delete", "Thread", thread.ID, "", fmt.Sprint(thread), "")
|
||
|
logEntry.Save()
|
||
|
|
||
|
return thread.Delete()
|
||
|
}
|
||
|
|
||
|
// Delete deletes the thread and its posts from the database.
|
||
|
func (thread *Thread) Delete() error {
|
||
|
for _, post := range thread.Posts() {
|
||
|
err := post.Delete()
|
||
|
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove activities
|
||
|
for activity := range StreamActivityCreates() {
|
||
|
if activity.ObjectID == thread.ID && activity.ObjectType == "Thread" {
|
||
|
err := activity.Delete()
|
||
|
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DB.Delete("Thread", thread.ID)
|
||
|
return nil
|
||
|
}
|