summaryrefslogtreecommitdiff
path: root/api/profiles/profiles.go
blob: 8e10e5f7bfa63b00d00c55f2f28ac6e576f017d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package profiles

import (
	"log"
	"net/http"
	"strings"

	"git.hatecomputers.club/hatecomputers/hatecomputers.club/adapters/files"
	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types"
	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database"
)

const MaxAvatarSize = 1024 * 1024 * 2 // 2MB
const AvatarPath = "avatars/"
const AvatarPrefix = "/uploads/avatars/"

func GetProfileContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain {
		if context.User == nil {
			return failure(context, req, resp)
		}

		(*context.TemplateData)["Profile"] = context.User
		return success(context, req, resp)
	}
}

func UpdateProfileContinuation(fileAdapter files.FilesAdapter, maxAvatarSize int, avatarPath string, avatarPrefix string) func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
	return func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
		return func(success types.Continuation, failure types.Continuation) types.ContinuationChain {
			formErrors := types.BannerMessages{
				Messages: []string{},
			}

			err := req.ParseMultipartForm(int64(maxAvatarSize))
			if err != nil {
				formErrors.Messages = append(formErrors.Messages, "avatar file too large")
			}

			if len(formErrors.Messages) == 0 {
				file, _, err := req.FormFile("avatar")
				if file != nil && err != nil {
					formErrors.Messages = append(formErrors.Messages, "error uploading avatar")
				} else if file != nil {
					defer file.Close()
					reader := http.MaxBytesReader(resp, file, int64(maxAvatarSize))
					defer reader.Close()

					_, err = fileAdapter.CreateFile(avatarPath+context.User.ID, reader)
					if err != nil {
						log.Println(err)
						formErrors.Messages = append(formErrors.Messages, "error saving avatar (is it too big?)")
					}
				}
			}

			context.User.Bio = strings.Trim(req.FormValue("bio"), "\n")
			context.User.Pronouns = req.FormValue("pronouns")
			context.User.Location = req.FormValue("location")
			context.User.Website = req.FormValue("website")
			context.User.Avatar = avatarPrefix + context.User.ID
			formErrors.Messages = append(formErrors.Messages, validateProfileUpdate(context.User)...)

			if len(formErrors.Messages) == 0 {
				_, err = database.SaveUser(context.DBConn, context.User)
				if err != nil {
					formErrors.Messages = append(formErrors.Messages, "error saving profile")
				}
			}

			(*context.TemplateData)["Profile"] = context.User
			(*context.TemplateData)["Error"] = formErrors

			if len(formErrors.Messages) > 0 {
				log.Println(formErrors.Messages)

				resp.WriteHeader(http.StatusBadRequest)
				return failure(context, req, resp)
			}

			formSuccess := types.BannerMessages{
				Messages: []string{"profile updated"},
			}
			(*context.TemplateData)["Success"] = formSuccess
			return success(context, req, resp)
		}
	}
}

func validateProfileUpdate(user *database.User) []string {
	errors := []string{}

	if (!strings.HasPrefix(user.Website, "https://") && !strings.HasPrefix(user.Website, "http://")) || len(user.Website) < 8 {
		errors = append(errors, "website must be a valid URL")
	}
	if len(user.Website) > 64 {
		errors = append(errors, "website cannot be longer than 64 characters")
	}

	if len(user.Pronouns) > 64 {
		errors = append(errors, "pronouns cannot be longer than 64 characters")
	}

	if len(user.Bio) > 128 {
		errors = append(errors, "bio cannot be longer than 128 characters")
	}

	newLines := strings.Count(user.Bio, "\n")
	if newLines > 8 {
		errors = append(errors, "message cannot contain more than 8 new lines")
	}

	if len(user.Location) > 32 {
		errors = append(errors, "location cannot be longer than 64 characters")
	}

	return errors
}