2018-05-17 07:05:00 +03:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2018 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2018-05-17 07:05:00 +03:00
package setting
import (
"errors"
"fmt"
2021-09-22 08:38:34 +03:00
"io"
2022-01-21 20:59:26 +03:00
"math/big"
2021-04-05 18:30:52 +03:00
"net/http"
2020-09-25 07:09:23 +03:00
"os"
"path/filepath"
2018-05-17 07:05:00 +03:00
"strings"
2021-09-24 14:32:56 +03:00
"code.gitea.io/gitea/models/db"
2022-03-29 09:29:02 +03:00
"code.gitea.io/gitea/models/organization"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-11 10:03:30 +03:00
user_model "code.gitea.io/gitea/models/user"
2018-05-17 07:05:00 +03:00
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
2022-06-26 17:19:22 +03:00
"code.gitea.io/gitea/modules/translation"
2021-06-05 15:32:19 +03:00
"code.gitea.io/gitea/modules/typesniffer"
2020-12-04 09:20:30 +03:00
"code.gitea.io/gitea/modules/util"
2021-01-26 18:36:53 +03:00
"code.gitea.io/gitea/modules/web"
2021-03-07 11:12:43 +03:00
"code.gitea.io/gitea/modules/web/middleware"
2021-07-28 12:42:56 +03:00
"code.gitea.io/gitea/services/agit"
2021-04-06 22:44:05 +03:00
"code.gitea.io/gitea/services/forms"
2022-07-28 06:59:39 +03:00
container_service "code.gitea.io/gitea/services/packages/container"
2021-11-22 18:21:55 +03:00
user_service "code.gitea.io/gitea/services/user"
2018-05-17 07:05:00 +03:00
)
const (
tplSettingsProfile base . TplName = "user/settings/profile"
2021-10-27 18:40:08 +03:00
tplSettingsAppearance base . TplName = "user/settings/appearance"
2018-05-17 07:05:00 +03:00
tplSettingsOrganization base . TplName = "user/settings/organization"
tplSettingsRepositories base . TplName = "user/settings/repos"
)
// Profile render user's profile page
func Profile ( ctx * context . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsSettingsProfile" ] = true
2021-06-27 21:47:35 +03:00
ctx . Data [ "AllowedUserVisibilityModes" ] = setting . Service . AllowedUserVisibilityModesSlice . ToVisibleTypeSlice ( )
2018-06-18 21:24:45 +03:00
2021-04-05 18:30:52 +03:00
ctx . HTML ( http . StatusOK , tplSettingsProfile )
2018-05-17 07:05:00 +03:00
}
2021-01-10 15:14:02 +03:00
// HandleUsernameChange handle username changes from user settings and admin interface
2021-11-24 12:49:20 +03:00
func HandleUsernameChange ( ctx * context . Context , user * user_model . User , newName string ) error {
2018-05-17 07:05:00 +03:00
// Non-local users are not allowed to change their username.
2021-01-10 15:14:02 +03:00
if ! user . IsLocal ( ) {
ctx . Flash . Error ( ctx . Tr ( "form.username_change_not_local_user" ) )
return fmt . Errorf ( ctx . Tr ( "form.username_change_not_local_user" ) )
2018-05-17 07:05:00 +03:00
}
// Check if user name has been changed
2021-01-10 15:14:02 +03:00
if user . LowerName != strings . ToLower ( newName ) {
2021-11-24 12:49:20 +03:00
if err := user_model . ChangeUserName ( user , newName ) ; err != nil {
2018-05-17 07:05:00 +03:00
switch {
2021-11-24 12:49:20 +03:00
case user_model . IsErrUserAlreadyExist ( err ) :
2018-05-17 07:05:00 +03:00
ctx . Flash . Error ( ctx . Tr ( "form.username_been_taken" ) )
2021-11-11 10:03:30 +03:00
case user_model . IsErrEmailAlreadyUsed ( err ) :
2018-05-17 07:05:00 +03:00
ctx . Flash . Error ( ctx . Tr ( "form.email_been_used" ) )
2021-11-24 12:49:20 +03:00
case db . IsErrNameReserved ( err ) :
2018-05-17 07:05:00 +03:00
ctx . Flash . Error ( ctx . Tr ( "user.form.name_reserved" , newName ) )
2021-11-24 12:49:20 +03:00
case db . IsErrNamePatternNotAllowed ( err ) :
2018-05-17 07:05:00 +03:00
ctx . Flash . Error ( ctx . Tr ( "user.form.name_pattern_not_allowed" , newName ) )
2021-11-24 12:49:20 +03:00
case db . IsErrNameCharsNotAllowed ( err ) :
2020-02-23 22:52:05 +03:00
ctx . Flash . Error ( ctx . Tr ( "user.form.name_chars_not_allowed" , newName ) )
2018-05-17 07:05:00 +03:00
default :
ctx . ServerError ( "ChangeUserName" , err )
}
2021-01-10 15:14:02 +03:00
return err
2018-05-17 07:05:00 +03:00
}
2021-06-02 15:03:59 +03:00
} else {
2021-12-12 18:48:20 +03:00
if err := repo_model . UpdateRepositoryOwnerNames ( user . ID , newName ) ; err != nil {
2021-06-02 15:03:59 +03:00
ctx . ServerError ( "UpdateRepository" , err )
return err
}
2018-05-17 07:05:00 +03:00
}
2021-07-28 12:42:56 +03:00
// update all agit flow pull request header
err := agit . UserNameChanged ( user , newName )
if err != nil {
ctx . ServerError ( "agit.UserNameChanged" , err )
return err
}
2022-07-28 06:59:39 +03:00
if err := container_service . UpdateRepositoryNames ( ctx , user , newName ) ; err != nil {
ctx . ServerError ( "UpdateRepositoryNames" , err )
return err
}
2021-06-02 15:03:59 +03:00
log . Trace ( "User name changed: %s -> %s" , user . Name , newName )
2021-01-10 15:14:02 +03:00
return nil
2018-05-17 07:05:00 +03:00
}
// ProfilePost response for change user's profile
2021-01-26 18:36:53 +03:00
func ProfilePost ( ctx * context . Context ) {
2021-04-06 22:44:05 +03:00
form := web . GetForm ( ctx ) . ( * forms . UpdateProfileForm )
2018-05-17 07:05:00 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsSettingsProfile" ] = true
if ctx . HasError ( ) {
2021-04-05 18:30:52 +03:00
ctx . HTML ( http . StatusOK , tplSettingsProfile )
2018-05-17 07:05:00 +03:00
return
}
2022-03-22 10:03:22 +03:00
if len ( form . Name ) != 0 && ctx . Doer . Name != form . Name {
log . Debug ( "Changing name for %s to %s" , ctx . Doer . Name , form . Name )
if err := HandleUsernameChange ( ctx , ctx . Doer , form . Name ) ; err != nil {
2021-01-10 15:14:02 +03:00
ctx . Redirect ( setting . AppSubURL + "/user/settings" )
return
}
2022-03-22 10:03:22 +03:00
ctx . Doer . Name = form . Name
ctx . Doer . LowerName = strings . ToLower ( form . Name )
2018-05-17 07:05:00 +03:00
}
2022-03-22 10:03:22 +03:00
ctx . Doer . FullName = form . FullName
ctx . Doer . KeepEmailPrivate = form . KeepEmailPrivate
ctx . Doer . Website = form . Website
ctx . Doer . Location = form . Location
ctx . Doer . Description = form . Description
ctx . Doer . KeepActivityPrivate = form . KeepActivityPrivate
ctx . Doer . Visibility = form . Visibility
if err := user_model . UpdateUserSetting ( ctx . Doer ) ; err != nil {
2021-11-11 10:03:30 +03:00
if _ , ok := err . ( user_model . ErrEmailAlreadyUsed ) ; ok {
2018-05-17 07:05:00 +03:00
ctx . Flash . Error ( ctx . Tr ( "form.email_been_used" ) )
ctx . Redirect ( setting . AppSubURL + "/user/settings" )
return
}
ctx . ServerError ( "UpdateUser" , err )
return
}
// Update the language to the one we just set
2022-03-22 10:03:22 +03:00
middleware . SetLocaleCookie ( ctx . Resp , ctx . Doer . Language , 0 )
2018-05-17 07:05:00 +03:00
2022-03-22 10:03:22 +03:00
log . Trace ( "User settings updated: %s" , ctx . Doer . Name )
2022-06-26 17:19:22 +03:00
ctx . Flash . Success ( translation . NewLocale ( ctx . Doer . Language ) . Tr ( "settings.update_profile_success" ) )
2018-05-17 07:05:00 +03:00
ctx . Redirect ( setting . AppSubURL + "/user/settings" )
}
// UpdateAvatarSetting update user's avatar
// FIXME: limit size.
2021-11-24 12:49:20 +03:00
func UpdateAvatarSetting ( ctx * context . Context , form * forms . AvatarForm , ctxUser * user_model . User ) error {
2021-04-06 22:44:05 +03:00
ctxUser . UseCustomAvatar = form . Source == forms . AvatarLocal
2018-05-17 07:05:00 +03:00
if len ( form . Gravatar ) > 0 {
2020-10-23 20:55:10 +03:00
if form . Avatar != nil {
ctxUser . Avatar = base . EncodeMD5 ( form . Gravatar )
} else {
ctxUser . Avatar = ""
}
2018-05-17 07:05:00 +03:00
ctxUser . AvatarEmail = form . Gravatar
}
2018-08-01 12:38:56 +03:00
if form . Avatar != nil && form . Avatar . Filename != "" {
2018-05-17 07:05:00 +03:00
fr , err := form . Avatar . Open ( )
if err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "Avatar.Open: %w" , err )
2018-05-17 07:05:00 +03:00
}
defer fr . Close ( )
2020-10-14 16:07:51 +03:00
if form . Avatar . Size > setting . Avatar . MaxFileSize {
2019-05-30 05:22:26 +03:00
return errors . New ( ctx . Tr ( "settings.uploaded_avatar_is_too_big" ) )
}
2021-09-22 08:38:34 +03:00
data , err := io . ReadAll ( fr )
2018-05-17 07:05:00 +03:00
if err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "io.ReadAll: %w" , err )
2018-05-17 07:05:00 +03:00
}
2021-06-05 15:32:19 +03:00
st := typesniffer . DetectContentType ( data )
if ! ( st . IsImage ( ) && ! st . IsSvgImage ( ) ) {
2018-05-17 07:05:00 +03:00
return errors . New ( ctx . Tr ( "settings.uploaded_avatar_not_a_image" ) )
}
2021-11-22 18:21:55 +03:00
if err = user_service . UploadAvatar ( ctxUser , data ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "UploadAvatar: %w" , err )
2018-05-17 07:05:00 +03:00
}
2020-10-14 16:07:51 +03:00
} else if ctxUser . UseCustomAvatar && ctxUser . Avatar == "" {
2018-05-17 07:05:00 +03:00
// No avatar is uploaded but setting has been changed to enable,
// generate a random one when needed.
2022-05-20 17:08:52 +03:00
if err := user_model . GenerateRandomAvatar ( ctx , ctxUser ) ; err != nil {
2019-06-12 22:41:28 +03:00
log . Error ( "GenerateRandomAvatar[%d]: %v" , ctxUser . ID , err )
2018-05-17 07:05:00 +03:00
}
}
2022-03-22 18:22:54 +03:00
if err := user_model . UpdateUserCols ( ctx , ctxUser , "avatar" , "avatar_email" , "use_custom_avatar" ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "UpdateUser: %w" , err )
2018-05-17 07:05:00 +03:00
}
return nil
}
// AvatarPost response for change user's avatar request
2021-01-26 18:36:53 +03:00
func AvatarPost ( ctx * context . Context ) {
2021-04-06 22:44:05 +03:00
form := web . GetForm ( ctx ) . ( * forms . AvatarForm )
2022-03-22 10:03:22 +03:00
if err := UpdateAvatarSetting ( ctx , form , ctx . Doer ) ; err != nil {
2018-05-17 07:05:00 +03:00
ctx . Flash . Error ( err . Error ( ) )
} else {
ctx . Flash . Success ( ctx . Tr ( "settings.update_avatar_success" ) )
}
ctx . Redirect ( setting . AppSubURL + "/user/settings" )
}
// DeleteAvatar render delete avatar page
func DeleteAvatar ( ctx * context . Context ) {
2022-03-22 10:03:22 +03:00
if err := user_service . DeleteAvatar ( ctx . Doer ) ; err != nil {
2018-05-17 07:05:00 +03:00
ctx . Flash . Error ( err . Error ( ) )
}
ctx . Redirect ( setting . AppSubURL + "/user/settings" )
}
// Organization render all the organization of the user
func Organization ( ctx * context . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsSettingsOrganization" ] = true
2021-11-22 16:51:45 +03:00
2022-03-29 09:29:02 +03:00
opts := organization . FindOrgOptions {
2021-11-22 16:51:45 +03:00
ListOptions : db . ListOptions {
PageSize : setting . UI . Admin . UserPagingNum ,
Page : ctx . FormInt ( "page" ) ,
} ,
2022-03-22 10:03:22 +03:00
UserID : ctx . Doer . ID ,
2021-11-22 16:51:45 +03:00
IncludePrivate : ctx . IsSigned ,
}
if opts . Page <= 0 {
opts . Page = 1
}
2022-03-29 09:29:02 +03:00
orgs , err := organization . FindOrgs ( opts )
2021-11-22 16:51:45 +03:00
if err != nil {
ctx . ServerError ( "FindOrgs" , err )
return
}
2022-03-29 09:29:02 +03:00
total , err := organization . CountOrgs ( opts )
2018-05-17 07:05:00 +03:00
if err != nil {
2021-11-22 16:51:45 +03:00
ctx . ServerError ( "CountOrgs" , err )
2018-05-17 07:05:00 +03:00
return
}
ctx . Data [ "Orgs" ] = orgs
2021-11-22 16:51:45 +03:00
pager := context . NewPagination ( int ( total ) , opts . PageSize , opts . Page , 5 )
pager . SetDefaultParams ( ctx )
ctx . Data [ "Page" ] = pager
2021-04-05 18:30:52 +03:00
ctx . HTML ( http . StatusOK , tplSettingsOrganization )
2018-05-17 07:05:00 +03:00
}
// Repos display a list of all repositories of the user
func Repos ( ctx * context . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsSettingsRepos" ] = true
2020-09-25 07:09:23 +03:00
ctx . Data [ "allowAdopt" ] = ctx . IsUserSiteAdmin ( ) || setting . Repository . AllowAdoptionOfUnadoptedRepositories
ctx . Data [ "allowDelete" ] = ctx . IsUserSiteAdmin ( ) || setting . Repository . AllowDeleteOfUnadoptedRepositories
2018-05-17 07:05:00 +03:00
2021-09-24 14:32:56 +03:00
opts := db . ListOptions {
2020-09-25 07:09:23 +03:00
PageSize : setting . UI . Admin . UserPagingNum ,
2021-07-29 04:42:15 +03:00
Page : ctx . FormInt ( "page" ) ,
2020-09-25 07:09:23 +03:00
}
if opts . Page <= 0 {
opts . Page = 1
2018-05-17 07:05:00 +03:00
}
2020-09-25 07:09:23 +03:00
start := ( opts . Page - 1 ) * opts . PageSize
end := start + opts . PageSize
2018-05-17 07:05:00 +03:00
2020-09-25 07:09:23 +03:00
adoptOrDelete := ctx . IsUserSiteAdmin ( ) || ( setting . Repository . AllowAdoptionOfUnadoptedRepositories && setting . Repository . AllowDeleteOfUnadoptedRepositories )
2022-03-22 10:03:22 +03:00
ctxUser := ctx . Doer
2020-09-25 07:09:23 +03:00
count := 0
if adoptOrDelete {
repoNames := make ( [ ] string , 0 , setting . UI . Admin . UserPagingNum )
2021-12-10 04:27:50 +03:00
repos := map [ string ] * repo_model . Repository { }
2020-09-25 07:09:23 +03:00
// We're going to iterate by pagesize.
2021-11-24 12:49:20 +03:00
root := user_model . UserPath ( ctxUser . Name )
2020-09-25 07:09:23 +03:00
if err := filepath . Walk ( root , func ( path string , info os . FileInfo , err error ) error {
2018-05-17 07:05:00 +03:00
if err != nil {
2020-12-31 10:45:54 +03:00
if os . IsNotExist ( err ) {
return nil
}
2020-09-25 07:09:23 +03:00
return err
2018-05-17 07:05:00 +03:00
}
2020-09-25 07:09:23 +03:00
if ! info . IsDir ( ) || path == root {
return nil
2018-05-17 07:05:00 +03:00
}
2020-09-25 07:09:23 +03:00
name := info . Name ( )
if ! strings . HasSuffix ( name , ".git" ) {
return filepath . SkipDir
}
name = name [ : len ( name ) - 4 ]
2021-12-12 18:48:20 +03:00
if repo_model . IsUsableRepoName ( name ) != nil || strings . ToLower ( name ) != name {
2020-09-25 07:09:23 +03:00
return filepath . SkipDir
}
if count >= start && count < end {
repoNames = append ( repoNames , name )
}
count ++
return filepath . SkipDir
} ) ; err != nil {
ctx . ServerError ( "filepath.Walk" , err )
return
2018-05-17 07:05:00 +03:00
}
2022-06-06 11:01:49 +03:00
userRepos , _ , err := repo_model . GetUserRepositories ( & repo_model . SearchRepoOptions {
2021-11-22 18:21:55 +03:00
Actor : ctxUser ,
Private : true ,
ListOptions : db . ListOptions {
Page : 1 ,
PageSize : setting . UI . Admin . UserPagingNum ,
} ,
LowerNames : repoNames ,
} )
if err != nil {
ctx . ServerError ( "GetUserRepositories" , err )
2020-09-25 07:09:23 +03:00
return
}
2021-11-22 18:21:55 +03:00
for _ , repo := range userRepos {
2020-09-25 07:09:23 +03:00
if repo . IsFork {
2022-12-03 05:48:26 +03:00
if err := repo . GetBaseRepo ( ctx ) ; err != nil {
2020-09-25 07:09:23 +03:00
ctx . ServerError ( "GetBaseRepo" , err )
return
}
}
repos [ repo . LowerName ] = repo
}
ctx . Data [ "Dirs" ] = repoNames
ctx . Data [ "ReposMap" ] = repos
} else {
2022-06-06 11:01:49 +03:00
repos , count64 , err := repo_model . GetUserRepositories ( & repo_model . SearchRepoOptions { Actor : ctxUser , Private : true , ListOptions : opts } )
2020-09-25 07:09:23 +03:00
if err != nil {
2021-11-22 18:21:55 +03:00
ctx . ServerError ( "GetUserRepositories" , err )
2020-09-25 07:09:23 +03:00
return
}
count = int ( count64 )
for i := range repos {
if repos [ i ] . IsFork {
2022-12-03 05:48:26 +03:00
if err := repos [ i ] . GetBaseRepo ( ctx ) ; err != nil {
2020-09-25 07:09:23 +03:00
ctx . ServerError ( "GetBaseRepo" , err )
return
}
}
}
ctx . Data [ "Repos" ] = repos
}
ctx . Data [ "Owner" ] = ctxUser
2022-06-20 13:02:49 +03:00
pager := context . NewPagination ( count , opts . PageSize , opts . Page , 5 )
2020-09-25 07:09:23 +03:00
pager . SetDefaultParams ( ctx )
ctx . Data [ "Page" ] = pager
2021-04-05 18:30:52 +03:00
ctx . HTML ( http . StatusOK , tplSettingsRepositories )
2018-05-17 07:05:00 +03:00
}
2021-10-27 18:40:08 +03:00
// Appearance render user's appearance settings
func Appearance ( ctx * context . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsSettingsAppearance" ] = true
2022-01-21 20:59:26 +03:00
var hiddenCommentTypes * big . Int
2022-03-22 10:03:22 +03:00
val , err := user_model . GetUserSetting ( ctx . Doer . ID , user_model . SettingsKeyHiddenCommentTypes )
2022-01-21 20:59:26 +03:00
if err != nil {
ctx . ServerError ( "GetUserSetting" , err )
return
}
hiddenCommentTypes , _ = new ( big . Int ) . SetString ( val , 10 ) // we can safely ignore the failed conversion here
ctx . Data [ "IsCommentTypeGroupChecked" ] = func ( commentTypeGroup string ) bool {
return forms . IsUserHiddenCommentTypeGroupChecked ( commentTypeGroup , hiddenCommentTypes )
}
2021-10-27 18:40:08 +03:00
ctx . HTML ( http . StatusOK , tplSettingsAppearance )
}
// UpdateUIThemePost is used to update users' specific theme
func UpdateUIThemePost ( ctx * context . Context ) {
form := web . GetForm ( ctx ) . ( * forms . UpdateThemeForm )
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsSettingsAppearance" ] = true
if ctx . HasError ( ) {
ctx . Redirect ( setting . AppSubURL + "/user/settings/appearance" )
return
}
if ! form . IsThemeExists ( ) {
ctx . Flash . Error ( ctx . Tr ( "settings.theme_update_error" ) )
ctx . Redirect ( setting . AppSubURL + "/user/settings/appearance" )
return
}
2022-03-22 10:03:22 +03:00
if err := user_model . UpdateUserTheme ( ctx . Doer , form . Theme ) ; err != nil {
2021-10-27 18:40:08 +03:00
ctx . Flash . Error ( ctx . Tr ( "settings.theme_update_error" ) )
ctx . Redirect ( setting . AppSubURL + "/user/settings/appearance" )
return
}
2022-03-22 10:03:22 +03:00
log . Trace ( "Update user theme: %s" , ctx . Doer . Name )
2021-10-27 18:40:08 +03:00
ctx . Flash . Success ( ctx . Tr ( "settings.theme_update_success" ) )
ctx . Redirect ( setting . AppSubURL + "/user/settings/appearance" )
}
// UpdateUserLang update a user's language
func UpdateUserLang ( ctx * context . Context ) {
form := web . GetForm ( ctx ) . ( * forms . UpdateLanguageForm )
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsSettingsAppearance" ] = true
if len ( form . Language ) != 0 {
if ! util . IsStringInSlice ( form . Language , setting . Langs ) {
ctx . Flash . Error ( ctx . Tr ( "settings.update_language_not_found" , form . Language ) )
ctx . Redirect ( setting . AppSubURL + "/user/settings/appearance" )
return
}
2022-03-22 10:03:22 +03:00
ctx . Doer . Language = form . Language
2021-10-27 18:40:08 +03:00
}
2022-03-22 10:03:22 +03:00
if err := user_model . UpdateUserSetting ( ctx . Doer ) ; err != nil {
2021-10-27 18:40:08 +03:00
ctx . ServerError ( "UpdateUserSetting" , err )
return
}
// Update the language to the one we just set
2022-03-22 10:03:22 +03:00
middleware . SetLocaleCookie ( ctx . Resp , ctx . Doer . Language , 0 )
2021-10-27 18:40:08 +03:00
2022-03-22 10:03:22 +03:00
log . Trace ( "User settings updated: %s" , ctx . Doer . Name )
2022-06-26 17:19:22 +03:00
ctx . Flash . Success ( translation . NewLocale ( ctx . Doer . Language ) . Tr ( "settings.update_language_success" ) )
2021-10-27 18:40:08 +03:00
ctx . Redirect ( setting . AppSubURL + "/user/settings/appearance" )
}
2022-01-21 20:59:26 +03:00
// UpdateUserHiddenComments update a user's shown comment types
func UpdateUserHiddenComments ( ctx * context . Context ) {
2022-03-22 10:03:22 +03:00
err := user_model . SetUserSetting ( ctx . Doer . ID , user_model . SettingsKeyHiddenCommentTypes , forms . UserHiddenCommentTypesFromRequest ( ctx ) . String ( ) )
2022-01-21 20:59:26 +03:00
if err != nil {
ctx . ServerError ( "SetUserSetting" , err )
return
}
2022-03-22 10:03:22 +03:00
log . Trace ( "User settings updated: %s" , ctx . Doer . Name )
2022-01-21 20:59:26 +03:00
ctx . Flash . Success ( ctx . Tr ( "settings.saved_successfully" ) )
ctx . Redirect ( setting . AppSubURL + "/user/settings/appearance" )
}