2014-04-10 22:20:58 +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 models
import (
2014-09-23 23:30:04 +04:00
"container/list"
2014-04-10 22:20:58 +04:00
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"time"
2014-07-26 08:24:27 +04:00
"github.com/Unknwon/com"
2014-04-10 22:20:58 +04:00
"github.com/gogits/gogs/modules/base"
2014-07-26 08:24:27 +04:00
"github.com/gogits/gogs/modules/git"
2014-04-10 22:20:58 +04:00
"github.com/gogits/gogs/modules/log"
2014-05-26 04:11:25 +04:00
"github.com/gogits/gogs/modules/setting"
2014-04-10 22:20:58 +04:00
)
2014-06-25 08:44:48 +04:00
type UserType int
2014-04-10 22:20:58 +04:00
const (
2014-06-25 08:44:48 +04:00
INDIVIDUAL UserType = iota // Historic reason to make it starts at 0.
ORGANIZATION
2014-04-10 22:20:58 +04:00
)
var (
2014-05-11 10:12:45 +04:00
ErrUserOwnRepos = errors . New ( "User still have ownership of repositories" )
2014-06-27 11:37:01 +04:00
ErrUserHasOrgs = errors . New ( "User still have membership of organization" )
2014-05-11 10:12:45 +04:00
ErrUserAlreadyExist = errors . New ( "User already exist" )
ErrUserNotExist = errors . New ( "User does not exist" )
2014-05-22 05:37:13 +04:00
ErrUserNotKeyOwner = errors . New ( "User does not the owner of public key" )
2014-05-11 10:12:45 +04:00
ErrEmailAlreadyUsed = errors . New ( "E-mail already used" )
ErrUserNameIllegal = errors . New ( "User name contains illegal characters" )
ErrLoginSourceNotExist = errors . New ( "Login source does not exist" )
ErrLoginSourceNotActived = errors . New ( "Login source is not actived" )
2014-05-15 22:46:04 +04:00
ErrUnsupportedLoginType = errors . New ( "Login source is unknown" )
2014-04-10 22:20:58 +04:00
)
// User represents the object of individual and member of organization.
type User struct {
Id int64
2014-08-28 18:29:00 +04:00
LowerName string ` xorm:"UNIQUE NOT NULL" `
Name string ` xorm:"UNIQUE NOT NULL" `
2014-05-01 16:26:41 +04:00
FullName string
2014-08-28 18:29:00 +04:00
Email string ` xorm:"UNIQUE NOT NULL" `
Passwd string ` xorm:"NOT NULL" `
2014-06-09 01:53:53 +04:00
LoginType LoginType
2014-08-28 18:29:00 +04:00
LoginSource int64 ` xorm:"NOT NULL DEFAULT 0" `
2014-05-11 07:56:04 +04:00
LoginName string
2014-06-25 08:44:48 +04:00
Type UserType
2014-08-24 17:09:05 +04:00
Orgs [ ] * User ` xorm:"-" `
Repos [ ] * Repository ` xorm:"-" `
2014-04-10 22:20:58 +04:00
NumFollowers int
NumFollowings int
NumStars int
NumRepos int
2014-08-28 18:29:00 +04:00
Avatar string ` xorm:"VARCHAR(2048) NOT NULL" `
AvatarEmail string ` xorm:"NOT NULL" `
2014-04-10 22:20:58 +04:00
Location string
Website string
IsActive bool
IsAdmin bool
Rands string ` xorm:"VARCHAR(10)" `
Salt string ` xorm:"VARCHAR(10)" `
2014-08-28 18:29:00 +04:00
Created time . Time ` xorm:"CREATED" `
Updated time . Time ` xorm:"UPDATED" `
2014-06-25 08:44:48 +04:00
// For organization.
2014-06-27 11:37:01 +04:00
Description string
NumTeams int
NumMembers int
2014-06-28 23:43:25 +04:00
Teams [ ] * Team ` xorm:"-" `
Members [ ] * User ` xorm:"-" `
2014-04-10 22:20:58 +04:00
}
2014-07-26 08:24:27 +04:00
// DashboardLink returns the user dashboard page link.
func ( u * User ) DashboardLink ( ) string {
if u . IsOrganization ( ) {
2014-09-20 04:11:34 +04:00
return setting . AppSubUrl + "/org/" + u . Name + "/dashboard/"
2014-07-26 08:24:27 +04:00
}
2014-09-20 04:11:34 +04:00
return setting . AppSubUrl + "/"
2014-07-26 08:24:27 +04:00
}
2014-04-10 22:20:58 +04:00
// HomeLink returns the user home page link.
2014-06-25 08:44:48 +04:00
func ( u * User ) HomeLink ( ) string {
2014-09-28 15:55:58 +04:00
return setting . AppSubUrl + "/" + u . Name
2014-04-10 22:20:58 +04:00
}
2014-06-06 06:07:35 +04:00
// AvatarLink returns user gravatar link.
2014-06-25 08:44:48 +04:00
func ( u * User ) AvatarLink ( ) string {
2014-05-26 04:11:25 +04:00
if setting . DisableGravatar {
2014-09-28 16:27:13 +04:00
return setting . AppSubUrl + "/img/avatar_default.jpg"
2014-05-26 04:11:25 +04:00
} else if setting . Service . EnableCacheAvatar {
2014-09-28 16:27:13 +04:00
return setting . AppSubUrl + "/avatar/" + u . Avatar
2014-04-10 22:20:58 +04:00
}
2014-06-25 08:44:48 +04:00
return "//1.gravatar.com/avatar/" + u . Avatar
2014-04-10 22:20:58 +04:00
}
// NewGitSig generates and returns the signature of given user.
2014-06-25 08:44:48 +04:00
func ( u * User ) NewGitSig ( ) * git . Signature {
2014-04-10 22:20:58 +04:00
return & git . Signature {
2014-06-25 08:44:48 +04:00
Name : u . Name ,
Email : u . Email ,
2014-04-10 22:20:58 +04:00
When : time . Now ( ) ,
}
}
// EncodePasswd encodes password to safe format.
2014-06-25 08:44:48 +04:00
func ( u * User ) EncodePasswd ( ) {
newPasswd := base . PBKDF2 ( [ ] byte ( u . Passwd ) , [ ] byte ( u . Salt ) , 10000 , 50 , sha256 . New )
u . Passwd = fmt . Sprintf ( "%x" , newPasswd )
}
2014-08-02 21:47:33 +04:00
// ValidtePassword checks if given password matches the one belongs to the user.
func ( u * User ) ValidtePassword ( passwd string ) bool {
newUser := & User { Passwd : passwd , Salt : u . Salt }
newUser . EncodePasswd ( )
return u . Passwd == newUser . Passwd
}
2014-06-28 08:40:07 +04:00
// IsOrganization returns true if user is actually a organization.
2014-06-25 08:44:48 +04:00
func ( u * User ) IsOrganization ( ) bool {
return u . Type == ORGANIZATION
}
2014-08-15 14:29:41 +04:00
// IsUserOrgOwner returns true if user is in the owner team of given organization.
func ( u * User ) IsUserOrgOwner ( orgId int64 ) bool {
return IsOrganizationOwner ( orgId , u . Id )
}
// IsPublicMember returns true if user public his/her membership in give organization.
func ( u * User ) IsPublicMember ( orgId int64 ) bool {
return IsPublicMembership ( orgId , u . Id )
}
2014-06-28 23:43:25 +04:00
// GetOrganizationCount returns count of membership of organization of user.
func ( u * User ) GetOrganizationCount ( ) ( int64 , error ) {
return x . Where ( "uid=?" , u . Id ) . Count ( new ( OrgUser ) )
}
2014-08-24 17:09:05 +04:00
// GetRepositories returns all repositories that user owns, including private repositories.
func ( u * User ) GetRepositories ( ) ( err error ) {
u . Repos , err = GetRepositories ( u . Id , true )
return err
}
2014-06-28 08:40:07 +04:00
// GetOrganizations returns all organizations that user belongs to.
2014-06-25 08:44:48 +04:00
func ( u * User ) GetOrganizations ( ) error {
ous , err := GetOrgUsersByUserId ( u . Id )
if err != nil {
return err
}
u . Orgs = make ( [ ] * User , len ( ous ) )
for i , ou := range ous {
u . Orgs [ i ] , err = GetUserById ( ou . OrgId )
if err != nil {
return err
}
}
return nil
2014-04-10 22:20:58 +04:00
}
2014-09-17 17:11:51 +04:00
// GetFullNameFallback returns Full Name if set, otherwise username
func ( u * User ) GetFullNameFallback ( ) string {
if u . FullName == "" {
return u . Name
}
return u . FullName
}
2014-04-10 22:20:58 +04:00
// IsUserExist checks if given user name exist,
// the user name should be noncased unique.
func IsUserExist ( name string ) ( bool , error ) {
if len ( name ) == 0 {
return false , nil
}
2014-06-21 08:51:41 +04:00
return x . Get ( & User { LowerName : strings . ToLower ( name ) } )
2014-04-10 22:20:58 +04:00
}
// IsEmailUsed returns true if the e-mail has been used.
func IsEmailUsed ( email string ) ( bool , error ) {
if len ( email ) == 0 {
return false , nil
}
2014-06-21 08:51:41 +04:00
return x . Get ( & User { Email : email } )
2014-04-10 22:20:58 +04:00
}
2014-10-25 02:43:17 +04:00
// GetUserSalt returns a ramdom user salt token.
2014-04-10 22:20:58 +04:00
func GetUserSalt ( ) string {
return base . GetRandomString ( 10 )
}
2014-06-25 08:44:48 +04:00
// CreateUser creates record of a new user.
2014-07-26 08:24:27 +04:00
func CreateUser ( u * User ) error {
2014-06-25 08:44:48 +04:00
if ! IsLegalName ( u . Name ) {
2014-07-26 08:24:27 +04:00
return ErrUserNameIllegal
2014-06-25 08:44:48 +04:00
}
isExist , err := IsUserExist ( u . Name )
if err != nil {
2014-07-26 08:24:27 +04:00
return err
2014-06-25 08:44:48 +04:00
} else if isExist {
2014-07-26 08:24:27 +04:00
return ErrUserAlreadyExist
2014-06-25 08:44:48 +04:00
}
isExist , err = IsEmailUsed ( u . Email )
if err != nil {
2014-07-26 08:24:27 +04:00
return err
2014-06-25 08:44:48 +04:00
} else if isExist {
2014-07-26 08:24:27 +04:00
return ErrEmailAlreadyUsed
2014-06-25 08:44:48 +04:00
}
u . LowerName = strings . ToLower ( u . Name )
u . Avatar = base . EncodeMd5 ( u . Email )
u . AvatarEmail = u . Email
u . Rands = GetUserSalt ( )
u . Salt = GetUserSalt ( )
u . EncodePasswd ( )
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
2014-07-26 08:24:27 +04:00
return err
2014-06-25 08:44:48 +04:00
}
if _ , err = sess . Insert ( u ) ; err != nil {
sess . Rollback ( )
2014-07-26 08:24:27 +04:00
return err
} else if err = os . MkdirAll ( UserPath ( u . Name ) , os . ModePerm ) ; err != nil {
2014-06-25 08:44:48 +04:00
sess . Rollback ( )
2014-07-26 08:24:27 +04:00
return err
} else if err = sess . Commit ( ) ; err != nil {
return err
2014-06-25 08:44:48 +04:00
}
2014-04-22 20:55:27 +04:00
2014-06-25 08:44:48 +04:00
// Auto-set admin for user whose ID is 1.
if u . Id == 1 {
u . IsAdmin = true
u . IsActive = true
_ , err = x . Id ( u . Id ) . UseBool ( ) . Update ( u )
}
2014-07-26 08:24:27 +04:00
return err
2014-06-25 08:44:48 +04:00
}
2014-07-07 12:15:08 +04:00
// CountUsers returns number of users.
func CountUsers ( ) int64 {
count , _ := x . Where ( "type=0" ) . Count ( new ( User ) )
return count
}
2014-04-10 22:20:58 +04:00
// GetUsers returns given number of user objects with offset.
2014-08-29 16:50:43 +04:00
func GetUsers ( num , offset int ) ( [ ] * User , error ) {
users := make ( [ ] * User , 0 , num )
2014-07-05 00:48:36 +04:00
err := x . Limit ( num , offset ) . Where ( "type=0" ) . Asc ( "id" ) . Find ( & users )
2014-04-10 22:20:58 +04:00
return users , err
}
// get user by erify code
func getVerifyUser ( code string ) ( user * User ) {
if len ( code ) <= base . TimeLimitCodeLength {
return nil
}
// use tail hex username query user
hexStr := code [ base . TimeLimitCodeLength : ]
if b , err := hex . DecodeString ( hexStr ) ; err == nil {
if user , err = GetUserByName ( string ( b ) ) ; user != nil {
return user
}
2014-07-26 08:24:27 +04:00
log . Error ( 4 , "user.getVerifyUser: %v" , err )
2014-04-10 22:20:58 +04:00
}
return nil
}
// verify active code when active account
func VerifyUserActiveCode ( code string ) ( user * User ) {
2014-05-26 04:11:25 +04:00
minutes := setting . Service . ActiveCodeLives
2014-04-10 22:20:58 +04:00
if user = getVerifyUser ( code ) ; user != nil {
// time limit code
prefix := code [ : base . TimeLimitCodeLength ]
2014-07-26 08:24:27 +04:00
data := com . ToStr ( user . Id ) + user . Email + user . LowerName + user . Passwd + user . Rands
2014-04-10 22:20:58 +04:00
if base . VerifyTimeLimitCode ( data , minutes , prefix ) {
return user
}
}
return nil
}
// ChangeUserName changes all corresponding setting from old user name to new one.
2014-07-26 08:24:27 +04:00
func ChangeUserName ( u * User , newUserName string ) ( err error ) {
if ! IsLegalName ( newUserName ) {
return ErrUserNameIllegal
}
2014-04-10 22:20:58 +04:00
newUserName = strings . ToLower ( newUserName )
// Update accesses of user.
accesses := make ( [ ] Access , 0 , 10 )
2014-07-26 08:24:27 +04:00
if err = x . Find ( & accesses , & Access { UserName : u . LowerName } ) ; err != nil {
2014-04-10 22:20:58 +04:00
return err
}
2014-06-21 08:51:41 +04:00
sess := x . NewSession ( )
2014-04-10 22:20:58 +04:00
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
for i := range accesses {
accesses [ i ] . UserName = newUserName
2014-07-26 08:24:27 +04:00
if strings . HasPrefix ( accesses [ i ] . RepoName , u . LowerName + "/" ) {
accesses [ i ] . RepoName = strings . Replace ( accesses [ i ] . RepoName , u . LowerName , newUserName , 1 )
2014-05-01 17:09:37 +04:00
}
if err = UpdateAccessWithSession ( sess , & accesses [ i ] ) ; err != nil {
return err
2014-04-10 22:20:58 +04:00
}
}
2014-07-26 08:24:27 +04:00
repos , err := GetRepositories ( u . Id , true )
2014-04-10 22:20:58 +04:00
if err != nil {
return err
}
for i := range repos {
accesses = make ( [ ] Access , 0 , 10 )
// Update accesses of user repository.
2014-07-26 08:24:27 +04:00
if err = x . Find ( & accesses , & Access { RepoName : u . LowerName + "/" + repos [ i ] . LowerName } ) ; err != nil {
2014-04-10 22:20:58 +04:00
return err
}
for j := range accesses {
2014-07-12 04:57:00 +04:00
// if the access is not the user's access (already updated above)
2014-07-26 08:24:27 +04:00
if accesses [ j ] . UserName != u . LowerName {
2014-07-12 04:57:00 +04:00
accesses [ j ] . RepoName = newUserName + "/" + repos [ i ] . LowerName
if err = UpdateAccessWithSession ( sess , & accesses [ j ] ) ; err != nil {
return err
}
2014-04-10 22:20:58 +04:00
}
}
}
// Change user directory name.
2014-07-26 08:24:27 +04:00
if err = os . Rename ( UserPath ( u . LowerName ) , UserPath ( newUserName ) ) ; err != nil {
2014-04-10 22:20:58 +04:00
sess . Rollback ( )
return err
}
return sess . Commit ( )
}
// UpdateUser updates user's information.
2014-07-26 08:24:27 +04:00
func UpdateUser ( u * User ) error {
2014-06-06 06:07:35 +04:00
u . LowerName = strings . ToLower ( u . Name )
2014-04-10 22:20:58 +04:00
2014-06-06 06:07:35 +04:00
if len ( u . Location ) > 255 {
u . Location = u . Location [ : 255 ]
2014-04-10 22:20:58 +04:00
}
2014-06-06 06:07:35 +04:00
if len ( u . Website ) > 255 {
u . Website = u . Website [ : 255 ]
2014-04-10 22:20:58 +04:00
}
2014-06-27 11:37:01 +04:00
if len ( u . Description ) > 255 {
u . Description = u . Description [ : 255 ]
}
2014-04-10 22:20:58 +04:00
2014-07-26 08:24:27 +04:00
_ , err := x . Id ( u . Id ) . AllCols ( ) . Update ( u )
2014-04-10 22:20:58 +04:00
return err
}
2014-06-28 08:40:07 +04:00
// TODO: need some kind of mechanism to record failure.
// DeleteUser completely and permanently deletes everything of user.
2014-06-27 11:37:01 +04:00
func DeleteUser ( u * User ) error {
2014-04-10 22:20:58 +04:00
// Check ownership of repository.
2014-06-27 11:37:01 +04:00
count , err := GetRepositoryCount ( u )
2014-04-10 22:20:58 +04:00
if err != nil {
2014-07-26 08:24:27 +04:00
return errors . New ( "GetRepositoryCount: " + err . Error ( ) )
2014-04-10 22:20:58 +04:00
} else if count > 0 {
return ErrUserOwnRepos
}
2014-06-27 11:37:01 +04:00
// Check membership of organization.
2014-06-28 23:43:25 +04:00
count , err = u . GetOrganizationCount ( )
2014-06-27 11:37:01 +04:00
if err != nil {
return errors . New ( "modesl.GetRepositories(GetOrganizationCount): " + err . Error ( ) )
} else if count > 0 {
return ErrUserHasOrgs
}
2014-04-10 22:20:58 +04:00
// TODO: check issues, other repos' commits
2014-06-28 08:40:07 +04:00
// TODO: roll backable in some point.
2014-04-10 22:20:58 +04:00
// Delete all followers.
2014-06-27 11:37:01 +04:00
if _ , err = x . Delete ( & Follow { FollowId : u . Id } ) ; err != nil {
2014-04-10 22:20:58 +04:00
return err
}
2014-04-11 21:24:19 +04:00
// Delete oauth2.
2014-06-27 11:37:01 +04:00
if _ , err = x . Delete ( & Oauth2 { Uid : u . Id } ) ; err != nil {
2014-04-12 05:47:39 +04:00
return err
}
2014-04-10 22:20:58 +04:00
// Delete all feeds.
2014-06-27 11:37:01 +04:00
if _ , err = x . Delete ( & Action { UserId : u . Id } ) ; err != nil {
2014-04-10 22:20:58 +04:00
return err
}
// Delete all watches.
2014-06-27 11:37:01 +04:00
if _ , err = x . Delete ( & Watch { UserId : u . Id } ) ; err != nil {
2014-04-10 22:20:58 +04:00
return err
}
// Delete all accesses.
2014-06-27 11:37:01 +04:00
if _ , err = x . Delete ( & Access { UserName : u . LowerName } ) ; err != nil {
2014-04-10 22:20:58 +04:00
return err
}
// Delete all SSH keys.
2014-05-07 00:28:52 +04:00
keys := make ( [ ] * PublicKey , 0 , 10 )
2014-06-27 11:37:01 +04:00
if err = x . Find ( & keys , & PublicKey { OwnerId : u . Id } ) ; err != nil {
2014-04-10 22:20:58 +04:00
return err
}
for _ , key := range keys {
2014-05-07 00:28:52 +04:00
if err = DeletePublicKey ( key ) ; err != nil {
2014-04-10 22:20:58 +04:00
return err
}
}
// Delete user directory.
2014-06-27 11:37:01 +04:00
if err = os . RemoveAll ( UserPath ( u . Name ) ) ; err != nil {
2014-04-10 22:20:58 +04:00
return err
}
2014-06-27 11:37:01 +04:00
_ , err = x . Delete ( u )
2014-06-21 08:51:41 +04:00
return err
}
// DeleteInactivateUsers deletes all inactivate users.
func DeleteInactivateUsers ( ) error {
_ , err := x . Where ( "is_active=?" , false ) . Delete ( new ( User ) )
2014-04-10 22:20:58 +04:00
return err
}
// UserPath returns the path absolute path of user repositories.
func UserPath ( userName string ) string {
2014-05-26 04:11:25 +04:00
return filepath . Join ( setting . RepoRootPath , strings . ToLower ( userName ) )
2014-04-10 22:20:58 +04:00
}
func GetUserByKeyId ( keyId int64 ) ( * User , error ) {
user := new ( User )
rawSql := "SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?"
2014-06-21 08:51:41 +04:00
has , err := x . Sql ( rawSql , keyId ) . Get ( user )
2014-04-10 22:20:58 +04:00
if err != nil {
return nil , err
} else if ! has {
2014-05-22 05:37:13 +04:00
return nil , ErrUserNotKeyOwner
2014-04-10 22:20:58 +04:00
}
return user , nil
}
2014-06-06 06:07:35 +04:00
// GetUserById returns the user object by given ID if exists.
2014-04-10 22:20:58 +04:00
func GetUserById ( id int64 ) ( * User , error ) {
2014-06-06 06:07:35 +04:00
u := new ( User )
2014-06-21 08:51:41 +04:00
has , err := x . Id ( id ) . Get ( u )
2014-04-10 22:20:58 +04:00
if err != nil {
return nil , err
2014-06-06 06:07:35 +04:00
} else if ! has {
2014-04-10 22:20:58 +04:00
return nil , ErrUserNotExist
}
2014-06-06 06:07:35 +04:00
return u , nil
2014-04-10 22:20:58 +04:00
}
2014-10-25 02:43:17 +04:00
// GetUserByName returns user by given name.
2014-04-10 22:20:58 +04:00
func GetUserByName ( name string ) ( * User , error ) {
if len ( name ) == 0 {
return nil , ErrUserNotExist
}
2014-10-25 02:43:17 +04:00
u := & User { LowerName : strings . ToLower ( name ) }
has , err := x . Get ( u )
2014-04-10 22:20:58 +04:00
if err != nil {
return nil , err
} else if ! has {
return nil , ErrUserNotExist
}
2014-10-25 02:43:17 +04:00
return u , nil
2014-04-10 22:20:58 +04:00
}
2014-10-12 02:02:48 +04:00
// GetUserEmailsByNames returns a list of e-mails corresponds to names.
2014-04-10 22:20:58 +04:00
func GetUserEmailsByNames ( names [ ] string ) [ ] string {
mails := make ( [ ] string , 0 , len ( names ) )
for _ , name := range names {
u , err := GetUserByName ( name )
if err != nil {
continue
}
mails = append ( mails , u . Email )
}
return mails
}
2014-05-08 00:51:14 +04:00
// GetUserIdsByNames returns a slice of ids corresponds to names.
func GetUserIdsByNames ( names [ ] string ) [ ] int64 {
ids := make ( [ ] int64 , 0 , len ( names ) )
for _ , name := range names {
u , err := GetUserByName ( name )
if err != nil {
continue
}
ids = append ( ids , u . Id )
}
return ids
}
2014-09-23 23:30:04 +04:00
// UserCommit represtns a commit with validation of user.
type UserCommit struct {
UserName string
* git . Commit
}
2014-09-26 16:55:13 +04:00
// ValidateCommitWithEmail chceck if author's e-mail of commit is corresponsind to a user.
func ValidateCommitWithEmail ( c * git . Commit ) ( uname string ) {
u , err := GetUserByEmail ( c . Author . Email )
if err == nil {
uname = u . Name
}
return uname
}
// ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users.
func ValidateCommitsWithEmails ( oldCommits * list . List ) * list . List {
2014-09-24 07:18:14 +04:00
emails := map [ string ] string { }
2014-09-23 23:30:04 +04:00
newCommits := list . New ( )
e := oldCommits . Front ( )
for e != nil {
c := e . Value . ( * git . Commit )
uname := ""
2014-09-24 07:18:14 +04:00
if v , ok := emails [ c . Author . Email ] ; ! ok {
u , err := GetUserByEmail ( c . Author . Email )
if err == nil {
uname = u . Name
}
emails [ c . Author . Email ] = uname
} else {
uname = v
2014-09-23 23:30:04 +04:00
}
newCommits . PushBack ( UserCommit {
UserName : uname ,
Commit : c ,
} )
e = e . Next ( )
}
return newCommits
}
2014-04-10 22:20:58 +04:00
// GetUserByEmail returns the user object by given e-mail if exists.
func GetUserByEmail ( email string ) ( * User , error ) {
if len ( email ) == 0 {
return nil , ErrUserNotExist
}
user := & User { Email : strings . ToLower ( email ) }
2014-06-21 08:51:41 +04:00
has , err := x . Get ( user )
2014-04-10 22:20:58 +04:00
if err != nil {
return nil , err
} else if ! has {
return nil , ErrUserNotExist
}
return user , nil
}
2014-05-01 07:48:01 +04:00
// SearchUserByName returns given number of users whose name contains keyword.
2014-08-26 14:11:15 +04:00
func SearchUserByName ( opt SearchOption ) ( us [ ] * User , err error ) {
2014-10-25 15:50:19 +04:00
opt . Keyword = FilterSQLInject ( opt . Keyword )
2014-08-26 14:11:15 +04:00
if len ( opt . Keyword ) == 0 {
2014-05-01 07:48:01 +04:00
return us , nil
}
2014-08-26 14:11:15 +04:00
opt . Keyword = strings . ToLower ( opt . Keyword )
2014-05-01 07:48:01 +04:00
2014-08-26 14:11:15 +04:00
us = make ( [ ] * User , 0 , opt . Limit )
err = x . Limit ( opt . Limit ) . Where ( "type=0" ) . And ( "lower_name like '%" + opt . Keyword + "%'" ) . Find ( & us )
2014-05-01 07:48:01 +04:00
return us , err
}
2014-04-10 22:20:58 +04:00
// Follow is connection request for receiving user notifycation.
type Follow struct {
Id int64
UserId int64 ` xorm:"unique(follow)" `
FollowId int64 ` xorm:"unique(follow)" `
}
// FollowUser marks someone be another's follower.
func FollowUser ( userId int64 , followId int64 ) ( err error ) {
2014-10-03 21:12:54 +04:00
sess := x . NewSession ( )
defer sess . Close ( )
sess . Begin ( )
2014-04-10 22:20:58 +04:00
2014-10-03 21:12:54 +04:00
if _ , err = sess . Insert ( & Follow { UserId : userId , FollowId : followId } ) ; err != nil {
sess . Rollback ( )
2014-04-10 22:20:58 +04:00
return err
}
rawSql := "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?"
2014-10-03 21:12:54 +04:00
if _ , err = sess . Exec ( rawSql , followId ) ; err != nil {
sess . Rollback ( )
2014-04-10 22:20:58 +04:00
return err
}
rawSql = "UPDATE `user` SET num_followings = num_followings + 1 WHERE id = ?"
2014-10-03 21:12:54 +04:00
if _ , err = sess . Exec ( rawSql , userId ) ; err != nil {
sess . Rollback ( )
2014-04-10 22:20:58 +04:00
return err
}
2014-10-03 21:12:54 +04:00
return sess . Commit ( )
2014-04-10 22:20:58 +04:00
}
// UnFollowUser unmarks someone be another's follower.
func UnFollowUser ( userId int64 , unFollowId int64 ) ( err error ) {
2014-06-21 08:51:41 +04:00
session := x . NewSession ( )
2014-04-10 22:20:58 +04:00
defer session . Close ( )
session . Begin ( )
if _ , err = session . Delete ( & Follow { UserId : userId , FollowId : unFollowId } ) ; err != nil {
session . Rollback ( )
return err
}
rawSql := "UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?"
if _ , err = session . Exec ( rawSql , unFollowId ) ; err != nil {
session . Rollback ( )
return err
}
rawSql = "UPDATE `user` SET num_followings = num_followings - 1 WHERE id = ?"
if _ , err = session . Exec ( rawSql , userId ) ; err != nil {
session . Rollback ( )
return err
}
return session . Commit ( )
}
2014-07-24 21:15:31 +04:00
func UpdateMentions ( userNames [ ] string , issueId int64 ) error {
users := make ( [ ] * User , 0 , len ( userNames ) )
if err := x . Where ( "name IN (?)" , strings . Join ( userNames , "\",\"" ) ) . OrderBy ( "name ASC" ) . Find ( & users ) ; err != nil {
return err
}
ids := make ( [ ] int64 , 0 , len ( userNames ) )
for _ , user := range users {
ids = append ( ids , user . Id )
if user . Type == INDIVIDUAL {
continue
}
if user . NumMembers == 0 {
continue
}
tempIds := make ( [ ] int64 , 0 , user . NumMembers )
orgUsers , err := GetOrgUsersByOrgId ( user . Id )
if err != nil {
return err
}
for _ , orgUser := range orgUsers {
tempIds = append ( tempIds , orgUser . Id )
}
ids = append ( ids , tempIds ... )
}
if err := UpdateIssueUserPairsByMentions ( ids , issueId ) ; err != nil {
return err
}
return nil
}