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