2014-03-10 12:54:52 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package user
import (
2014-11-21 18:58:08 +03:00
"io/ioutil"
2014-08-25 22:07:08 +04:00
"strings"
2014-07-26 08:24:27 +04:00
"github.com/Unknwon/com"
2014-03-11 04:48:58 +04:00
2014-03-10 12:54:52 +04:00
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
2014-12-17 18:42:54 +03:00
"github.com/gogits/gogs/modules/mailer"
2014-03-15 17:17:16 +04:00
"github.com/gogits/gogs/modules/middleware"
2014-09-14 21:35:22 +04:00
"github.com/gogits/gogs/modules/setting"
2014-03-10 12:54:52 +04:00
)
2014-06-23 07:11:12 +04:00
const (
2014-11-12 14:48:50 +03:00
SETTINGS_PROFILE base . TplName = "user/settings/profile"
SETTINGS_PASSWORD base . TplName = "user/settings/password"
2014-12-17 18:42:54 +03:00
SETTINGS_EMAILS base . TplName = "user/settings/email"
2014-11-12 14:48:50 +03:00
SETTINGS_SSH_KEYS base . TplName = "user/settings/sshkeys"
SETTINGS_SOCIAL base . TplName = "user/settings/social"
SETTINGS_APPLICATIONS base . TplName = "user/settings/applications"
SETTINGS_DELETE base . TplName = "user/settings/delete"
NOTIFICATION base . TplName = "user/notification"
SECURITY base . TplName = "user/security"
2014-06-23 07:11:12 +04:00
)
2014-07-26 08:24:27 +04:00
func Settings ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsProfile" ] = true
ctx . HTML ( 200 , SETTINGS_PROFILE )
2014-04-11 00:36:50 +04:00
}
2014-07-26 08:24:27 +04:00
func SettingsPost ( ctx * middleware . Context , form auth . UpdateProfileForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsProfile" ] = true
2014-03-13 11:39:18 +04:00
2014-04-11 00:36:50 +04:00
if ctx . HasError ( ) {
2014-07-26 08:24:27 +04:00
ctx . HTML ( 200 , SETTINGS_PROFILE )
2014-03-13 11:44:56 +04:00
return
2014-03-13 11:39:18 +04:00
}
2014-04-04 00:33:27 +04:00
// Check if user name has been changed.
2014-05-24 23:28:31 +04:00
if ctx . User . Name != form . UserName {
2014-04-04 00:33:27 +04:00
isExist , err := models . IsUserExist ( form . UserName )
if err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "IsUserExist" , err )
2014-04-04 00:33:27 +04:00
return
} else if isExist {
2014-07-26 08:24:27 +04:00
ctx . RenderWithErr ( ctx . Tr ( "form.username_been_taken" ) , SETTINGS_PROFILE , & form )
2014-04-04 00:33:27 +04:00
return
2014-05-24 23:28:31 +04:00
} else if err = models . ChangeUserName ( ctx . User , form . UserName ) ; err != nil {
2014-07-26 08:24:27 +04:00
if err == models . ErrUserNameIllegal {
ctx . Flash . Error ( ctx . Tr ( "form.illegal_username" ) )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/settings" )
2014-07-26 08:24:27 +04:00
return
} else {
ctx . Handle ( 500 , "ChangeUserName" , err )
}
2014-04-04 00:33:27 +04:00
return
}
2014-07-26 08:24:27 +04:00
log . Trace ( "User name changed: %s -> %s" , ctx . User . Name , form . UserName )
2014-05-24 23:28:31 +04:00
ctx . User . Name = form . UserName
2014-03-13 11:39:18 +04:00
}
2014-05-24 23:28:31 +04:00
ctx . User . FullName = form . FullName
ctx . User . Email = form . Email
ctx . User . Website = form . Website
ctx . User . Location = form . Location
ctx . User . Avatar = base . EncodeMd5 ( form . Avatar )
ctx . User . AvatarEmail = form . Avatar
if err := models . UpdateUser ( ctx . User ) ; err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "UpdateUser" , err )
2014-03-13 11:39:18 +04:00
return
}
2014-07-26 08:24:27 +04:00
log . Trace ( "User setting updated: %s" , ctx . User . Name )
ctx . Flash . Success ( ctx . Tr ( "settings.update_profile_success" ) )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/settings" )
2014-03-10 12:54:52 +04:00
}
2014-11-21 18:58:08 +03:00
// FIXME: limit size.
func SettingsAvatar ( ctx * middleware . Context , form auth . UploadAvatarForm ) {
defer ctx . Redirect ( setting . AppSubUrl + "/user/settings" )
2014-11-21 20:51:36 +03:00
ctx . User . UseCustomAvatar = form . Enable
2014-11-21 18:58:08 +03:00
if form . Avatar != nil {
fr , err := form . Avatar . Open ( )
if err != nil {
ctx . Flash . Error ( err . Error ( ) )
return
}
data , err := ioutil . ReadAll ( fr )
if err != nil {
ctx . Flash . Error ( err . Error ( ) )
return
}
if _ , ok := base . IsImageFile ( data ) ; ! ok {
ctx . Flash . Error ( ctx . Tr ( "settings.uploaded_avatar_not_a_image" ) )
return
}
if err = ctx . User . UploadAvatar ( data ) ; err != nil {
ctx . Flash . Error ( err . Error ( ) )
return
}
2014-11-22 18:22:53 +03:00
} else {
// In case no avatar at all.
if form . Enable && ! com . IsFile ( ctx . User . CustomAvatarPath ( ) ) {
ctx . Flash . Error ( ctx . Tr ( "settings.no_custom_avatar_available" ) )
return
}
2014-11-21 18:58:08 +03:00
}
2014-11-22 18:22:53 +03:00
if err := models . UpdateUser ( ctx . User ) ; err != nil {
ctx . Flash . Error ( err . Error ( ) )
return
}
2014-11-21 20:51:36 +03:00
ctx . Flash . Success ( ctx . Tr ( "settings.update_avatar_success" ) )
2014-11-21 18:58:08 +03:00
}
2014-12-17 18:42:54 +03:00
func SettingsEmails ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsEmails" ] = true
var err error
ctx . Data [ "Emails" ] , err = models . GetEmailAddresses ( ctx . User . Id )
if err != nil {
ctx . Handle ( 500 , "email.GetEmailAddresses" , err )
return
}
ctx . HTML ( 200 , SETTINGS_EMAILS )
}
func SettingsEmailPost ( ctx * middleware . Context , form auth . AddEmailForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsEmails" ] = true
var err error
ctx . Data [ "Emails" ] , err = models . GetEmailAddresses ( ctx . User . Id )
if err != nil {
ctx . Handle ( 500 , "email.GetEmailAddresses" , err )
return
}
// Delete Email address.
if ctx . Query ( "_method" ) == "DELETE" {
id := com . StrTo ( ctx . Query ( "id" ) ) . MustInt64 ( )
if id <= 0 {
return
}
if err = models . DeleteEmailAddress ( & models . EmailAddress { Id : id } ) ; err != nil {
ctx . Handle ( 500 , "DeleteEmail" , err )
} else {
log . Trace ( "Email address deleted: %s" , ctx . User . Name )
ctx . Redirect ( setting . AppSubUrl + "/user/settings/email" )
}
return
}
// Make emailaddress primary.
if ctx . Query ( "_method" ) == "PRIMARY" {
id := com . StrTo ( ctx . Query ( "id" ) ) . MustInt64 ( )
if id <= 0 {
return
}
if err = models . MakeEmailPrimary ( & models . EmailAddress { Id : id } ) ; err != nil {
ctx . Handle ( 500 , "MakeEmailPrimary" , err )
} else {
log . Trace ( "Email made primary: %s" , ctx . User . Name )
ctx . Redirect ( setting . AppSubUrl + "/user/settings/email" )
}
return
}
// Add Email address.
if ctx . Req . Method == "POST" {
if ctx . HasError ( ) {
ctx . HTML ( 200 , SETTINGS_EMAILS )
return
}
cleanEmail := strings . Replace ( form . Email , "\n" , "" , - 1 )
e := & models . EmailAddress {
2014-12-20 10:26:51 +03:00
Uid : ctx . User . Id ,
2014-12-17 18:42:54 +03:00
Email : cleanEmail ,
IsActivated : ! setting . Service . RegisterEmailConfirm ,
}
if err := models . AddEmailAddress ( e ) ; err != nil {
if err == models . ErrEmailAlreadyUsed {
ctx . RenderWithErr ( ctx . Tr ( "form.email_has_been_used" ) , SETTINGS_EMAILS , & form )
return
}
ctx . Handle ( 500 , "email.AddEmailAddress" , err )
return
} else {
// Send confirmation e-mail
if setting . Service . RegisterEmailConfirm {
mailer . SendActivateEmail ( ctx . Render , ctx . User , e )
if err := ctx . Cache . Put ( "MailResendLimit_" + ctx . User . LowerName , ctx . User . LowerName , 180 ) ; err != nil {
log . Error ( 4 , "Set cache(MailResendLimit) fail: %v" , err )
}
ctx . Flash . Success ( ctx . Tr ( "settings.add_email_success_confirmation_email_sent" ) )
} else {
ctx . Flash . Success ( ctx . Tr ( "settings.add_email_success" ) )
}
log . Trace ( "Email address added: %s" , e . Email )
ctx . Redirect ( setting . AppSubUrl + "/user/settings/email" )
return
}
}
ctx . HTML ( 200 , SETTINGS_EMAILS )
}
2014-07-26 08:24:27 +04:00
func SettingsPassword ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsPassword" ] = true
ctx . HTML ( 200 , SETTINGS_PASSWORD )
2014-04-11 02:09:57 +04:00
}
2014-07-26 08:24:27 +04:00
func SettingsPasswordPost ( ctx * middleware . Context , form auth . ChangePasswordForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsPassword" ] = true
2014-03-14 07:24:08 +04:00
2014-04-11 02:09:57 +04:00
if ctx . HasError ( ) {
2014-07-26 08:24:27 +04:00
ctx . HTML ( 200 , SETTINGS_PASSWORD )
2014-03-14 09:12:07 +04:00
return
}
2014-03-13 12:06:35 +04:00
2014-04-11 02:09:57 +04:00
tmpUser := & models . User {
2014-07-26 08:24:27 +04:00
Passwd : form . OldPassword ,
2014-05-24 23:28:31 +04:00
Salt : ctx . User . Salt ,
2014-04-11 02:09:57 +04:00
}
tmpUser . EncodePasswd ( )
2014-05-24 23:28:31 +04:00
if ctx . User . Passwd != tmpUser . Passwd {
2014-07-26 08:24:27 +04:00
ctx . Flash . Error ( ctx . Tr ( "settings.password_incorrect" ) )
} else if form . Password != form . Retype {
ctx . Flash . Error ( ctx . Tr ( "form.password_not_match" ) )
2014-03-13 12:06:35 +04:00
} else {
2014-07-26 08:24:27 +04:00
ctx . User . Passwd = form . Password
2014-05-24 23:28:31 +04:00
ctx . User . Salt = models . GetUserSalt ( )
ctx . User . EncodePasswd ( )
if err := models . UpdateUser ( ctx . User ) ; err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "UpdateUser" , err )
2014-03-13 12:06:35 +04:00
return
}
2014-07-26 08:24:27 +04:00
log . Trace ( "User password updated: %s" , ctx . User . Name )
ctx . Flash . Success ( ctx . Tr ( "settings.change_password_success" ) )
2014-03-13 12:06:35 +04:00
}
2014-07-26 08:24:27 +04:00
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/settings/password" )
2014-03-13 12:06:35 +04:00
}
2014-07-26 08:24:27 +04:00
func SettingsSSHKeys ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsSSHKeys" ] = true
2014-07-20 20:02:59 +04:00
2014-07-26 08:24:27 +04:00
var err error
2014-11-12 14:48:50 +03:00
ctx . Data [ "Keys" ] , err = models . ListPublicKeys ( ctx . User . Id )
2014-07-20 20:02:59 +04:00
if err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "ssh.ListPublicKey" , err )
return
2014-07-20 20:02:59 +04:00
}
2014-07-26 08:24:27 +04:00
ctx . HTML ( 200 , SETTINGS_SSH_KEYS )
2014-07-20 20:02:59 +04:00
}
2014-07-26 08:24:27 +04:00
func SettingsSSHKeysPost ( ctx * middleware . Context , form auth . AddSSHKeyForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsSSHKeys" ] = true
var err error
2014-11-12 14:48:50 +03:00
ctx . Data [ "Keys" ] , err = models . ListPublicKeys ( ctx . User . Id )
2014-07-26 08:24:27 +04:00
if err != nil {
ctx . Handle ( 500 , "ssh.ListPublicKey" , err )
return
}
2014-03-11 04:48:58 +04:00
// Delete SSH key.
2014-07-26 08:24:27 +04:00
if ctx . Query ( "_method" ) == "DELETE" {
id := com . StrTo ( ctx . Query ( "id" ) ) . MustInt64 ( )
if id <= 0 {
2014-03-10 17:12:49 +04:00
return
}
2014-03-11 04:48:58 +04:00
2014-05-07 00:28:52 +04:00
if err = models . DeletePublicKey ( & models . PublicKey { Id : id } ) ; err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "DeletePublicKey" , err )
2014-03-10 17:12:49 +04:00
} else {
2014-07-26 08:24:27 +04:00
log . Trace ( "SSH key deleted: %s" , ctx . User . Name )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/settings/ssh" )
2014-03-10 17:12:49 +04:00
}
2014-03-11 07:41:38 +04:00
return
2014-03-10 17:12:49 +04:00
}
2014-03-11 04:48:58 +04:00
// Add new SSH key.
2014-03-15 18:34:33 +04:00
if ctx . Req . Method == "POST" {
2014-04-14 05:00:12 +04:00
if ctx . HasError ( ) {
2014-07-26 08:24:27 +04:00
ctx . HTML ( 200 , SETTINGS_SSH_KEYS )
2014-03-11 04:48:58 +04:00
return
}
2015-01-02 16:38:11 +03:00
// Parse openssh style string from form content
content , err := models . ParseKeyString ( form . Content )
if err != nil {
ctx . Flash . Error ( ctx . Tr ( "form.invalid_ssh_key" , err . Error ( ) ) )
ctx . Redirect ( setting . AppSubUrl + "/user/settings/ssh" )
return
}
2014-08-25 19:54:50 +04:00
2015-01-02 16:38:11 +03:00
if ok , err := models . CheckPublicKeyString ( content ) ; ! ok {
2014-10-12 05:04:42 +04:00
if err == models . ErrKeyUnableVerify {
ctx . Flash . Info ( ctx . Tr ( "form.unable_verify_ssh_key" ) )
} else {
ctx . Flash . Error ( ctx . Tr ( "form.invalid_ssh_key" , err . Error ( ) ) )
ctx . Redirect ( setting . AppSubUrl + "/user/settings/ssh" )
return
}
2014-05-06 00:21:43 +04:00
}
2014-04-28 01:01:39 +04:00
k := & models . PublicKey {
OwnerId : ctx . User . Id ,
2014-07-26 08:24:27 +04:00
Name : form . SSHTitle ,
2015-01-02 16:38:11 +03:00
Content : content ,
2014-03-10 12:54:52 +04:00
}
2014-03-11 04:48:58 +04:00
if err := models . AddPublicKey ( k ) ; err != nil {
2014-07-26 08:24:27 +04:00
if err == models . ErrKeyAlreadyExist {
ctx . RenderWithErr ( ctx . Tr ( "form.ssh_key_been_used" ) , SETTINGS_SSH_KEYS , & form )
2014-03-16 14:25:16 +04:00
return
}
2014-04-14 05:00:12 +04:00
ctx . Handle ( 500 , "ssh.AddPublicKey" , err )
2014-03-10 12:54:52 +04:00
return
} else {
2014-07-26 08:24:27 +04:00
log . Trace ( "SSH key added: %s" , ctx . User . Name )
ctx . Flash . Success ( ctx . Tr ( "settings.add_key_success" ) )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/settings/ssh" )
2014-04-14 05:00:12 +04:00
return
2014-03-10 12:54:52 +04:00
}
}
2014-03-11 04:48:58 +04:00
2014-07-26 08:24:27 +04:00
ctx . HTML ( 200 , SETTINGS_SSH_KEYS )
2014-03-10 12:54:52 +04:00
}
2014-03-14 13:12:28 +04:00
2014-07-26 08:24:27 +04:00
func SettingsSocial ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsSocial" ] = true
2014-08-10 04:25:02 +04:00
// Unbind social account.
remove , _ := com . StrTo ( ctx . Query ( "remove" ) ) . Int64 ( )
if remove > 0 {
if err := models . DeleteOauth2ById ( remove ) ; err != nil {
ctx . Handle ( 500 , "DeleteOauth2ById" , err )
return
}
ctx . Flash . Success ( ctx . Tr ( "settings.unbind_success" ) )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/settings/social" )
2014-08-10 04:25:02 +04:00
return
}
socials , err := models . GetOauthByUserId ( ctx . User . Id )
if err != nil {
ctx . Handle ( 500 , "GetOauthByUserId" , err )
return
}
ctx . Data [ "Socials" ] = socials
2014-07-26 08:24:27 +04:00
ctx . HTML ( 200 , SETTINGS_SOCIAL )
2014-03-14 13:12:28 +04:00
}
2014-11-12 14:48:50 +03:00
func SettingsApplications ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsApplications" ] = true
// Delete access token.
remove , _ := com . StrTo ( ctx . Query ( "remove" ) ) . Int64 ( )
if remove > 0 {
if err := models . DeleteAccessTokenById ( remove ) ; err != nil {
ctx . Handle ( 500 , "DeleteAccessTokenById" , err )
return
}
ctx . Flash . Success ( ctx . Tr ( "settings.delete_token_success" ) )
ctx . Redirect ( setting . AppSubUrl + "/user/settings/applications" )
return
}
tokens , err := models . ListAccessTokens ( ctx . User . Id )
if err != nil {
ctx . Handle ( 500 , "ListAccessTokens" , err )
return
}
ctx . Data [ "Tokens" ] = tokens
ctx . HTML ( 200 , SETTINGS_APPLICATIONS )
}
// FIXME: split to two different functions and pages to handle access token and oauth2
func SettingsApplicationsPost ( ctx * middleware . Context , form auth . NewAccessTokenForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsApplications" ] = true
switch ctx . Query ( "type" ) {
case "token" :
if ctx . HasError ( ) {
ctx . HTML ( 200 , SETTINGS_APPLICATIONS )
return
}
t := & models . AccessToken {
Uid : ctx . User . Id ,
Name : form . Name ,
}
if err := models . NewAccessToken ( t ) ; err != nil {
ctx . Handle ( 500 , "NewAccessToken" , err )
return
}
ctx . Flash . Success ( ctx . Tr ( "settings.generate_token_succees" ) )
ctx . Flash . Info ( t . Sha1 )
}
ctx . Redirect ( setting . AppSubUrl + "/user/settings/applications" )
}
2014-07-26 08:24:27 +04:00
func SettingsDelete ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "settings" )
ctx . Data [ "PageIsUserSettings" ] = true
ctx . Data [ "PageIsSettingsDelete" ] = true
if ctx . Req . Method == "POST" {
// tmpUser := models.User{
// Passwd: ctx.Query("password"),
// Salt: ctx.User.Salt,
// }
// tmpUser.EncodePasswd()
// if tmpUser.Passwd != ctx.User.Passwd {
// ctx.Flash.Error("Password is not correct. Make sure you are owner of this account.")
// } else {
if err := models . DeleteUser ( ctx . User ) ; err != nil {
switch err {
case models . ErrUserOwnRepos :
ctx . Flash . Error ( ctx . Tr ( "form.still_own_repo" ) )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/settings/delete" )
2014-11-13 13:27:01 +03:00
case models . ErrUserHasOrgs :
ctx . Flash . Error ( ctx . Tr ( "form.still_has_org" ) )
ctx . Redirect ( setting . AppSubUrl + "/user/settings/delete" )
2014-07-26 08:24:27 +04:00
default :
ctx . Handle ( 500 , "DeleteUser" , err )
}
} else {
log . Trace ( "Account deleted: %s" , ctx . User . Name )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/" )
2014-07-26 08:24:27 +04:00
}
2014-08-14 10:12:21 +04:00
return
2014-07-26 08:24:27 +04:00
}
ctx . HTML ( 200 , SETTINGS_DELETE )
2014-03-14 13:12:28 +04:00
}