1/*
2 * Copyright © 2018-2019, 2021 A Bunch Tell LLC.
3 *
4 * This file is part of WriteFreely.
5 *
6 * WriteFreely is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License, included
8 * in the LICENSE file in this source code package.
9 */
10
11package writefreely
12
13import (
14	"time"
15
16	"github.com/guregu/null/zero"
17	"github.com/writeas/web-core/data"
18	"github.com/writeas/web-core/log"
19	"github.com/writefreely/writefreely/key"
20)
21
22type UserStatus int
23
24const (
25	UserActive = iota
26	UserSilenced
27)
28
29type (
30	userCredentials struct {
31		Alias string `json:"alias" schema:"alias"`
32		Pass  string `json:"pass" schema:"pass"`
33		Email string `json:"email" schema:"email"`
34		Web   bool   `json:"web" schema:"-"`
35		To    string `json:"-" schema:"to"`
36
37		EmailLogin bool `json:"via_email" schema:"via_email"`
38	}
39
40	userRegistration struct {
41		userCredentials
42		InviteCode string `json:"invite_code" schema:"invite_code"`
43		Honeypot   string `json:"fullname" schema:"fullname"`
44		Normalize  bool   `json:"normalize" schema:"normalize"`
45		Signup     bool   `json:"signup" schema:"signup"`
46
47		// Feature fields
48		Description  string `json:"description" schema:"description"`
49		Monetization string `json:"monetization" schema:"monetization"`
50	}
51
52	// AuthUser contains information for a newly authenticated user (either
53	// from signing up or logging in).
54	AuthUser struct {
55		AccessToken string `json:"access_token,omitempty"`
56		Password    string `json:"password,omitempty"`
57		User        *User  `json:"user"`
58
59		// Verbose user data
60		Posts       *[]PublicPost `json:"posts,omitempty"`
61		Collections *[]Collection `json:"collections,omitempty"`
62	}
63
64	// User is a consistent user object in the database and all contexts (auth
65	// and non-auth) in the API.
66	User struct {
67		ID         int64       `json:"-"`
68		Username   string      `json:"username"`
69		HashedPass []byte      `json:"-"`
70		HasPass    bool        `json:"has_pass"`
71		Email      zero.String `json:"email"`
72		Created    time.Time   `json:"created"`
73		Status     UserStatus  `json:"status"`
74
75		clearEmail string `json:"email"`
76	}
77
78	userMeStats struct {
79		TotalCollections, TotalArticles, CollectionPosts uint64
80	}
81
82	ExportUser struct {
83		*User
84		Collections    *[]CollectionObj `json:"collections"`
85		AnonymousPosts []PublicPost     `json:"posts"`
86	}
87
88	PublicUser struct {
89		Username string `json:"username"`
90	}
91)
92
93// EmailClear decrypts and returns the user's email, caching it in the user
94// object.
95func (u *User) EmailClear(keys *key.Keychain) string {
96	if u.clearEmail != "" {
97		return u.clearEmail
98	}
99
100	if u.Email.Valid && u.Email.String != "" {
101		email, err := data.Decrypt(keys.EmailKey, []byte(u.Email.String))
102		if err != nil {
103			log.Error("Error decrypting user email: %v", err)
104		} else {
105			u.clearEmail = string(email)
106			return u.clearEmail
107		}
108	}
109	return ""
110}
111
112func (u User) CreatedFriendly() string {
113	/*
114		// TODO: accept a locale in this method and use that for the format
115		var loc monday.Locale = monday.LocaleEnUS
116		return monday.Format(u.Created, monday.DateTimeFormatsByLocale[loc], loc)
117	*/
118	return u.Created.Format("January 2, 2006, 3:04 PM")
119}
120
121// Cookie strips down an AuthUser to contain only information necessary for
122// cookies.
123func (u User) Cookie() *User {
124	u.HashedPass = []byte{}
125
126	return &u
127}
128
129func (u *User) IsAdmin() bool {
130	// TODO: get this from database
131	return u.ID == 1
132}
133
134func (u *User) IsSilenced() bool {
135	return u.Status&UserSilenced != 0
136}
137