2015-12-21 15:24:11 +03:00
// Copyright 2015 The Gogs Authors. All rights reserved.
2019-02-18 19:00:27 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2015-12-21 15:24:11 +03:00
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package user
import (
"fmt"
2015-12-25 13:25:47 +03:00
"path"
2015-12-21 15:24:11 +03:00
"strings"
2016-07-24 09:32:46 +03:00
"github.com/Unknwon/paginater"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
2017-10-27 00:16:13 +03:00
"code.gitea.io/gitea/modules/util"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/routers/repo"
2015-12-21 15:24:11 +03:00
)
const (
2016-11-18 06:03:03 +03:00
tplFollowers base . TplName = "user/meta/followers"
tplStars base . TplName = "user/meta/stars"
2015-12-21 15:24:11 +03:00
)
2016-11-18 06:03:03 +03:00
// GetUserByName get user by name
2016-03-11 19:56:52 +03:00
func GetUserByName ( ctx * context . Context , name string ) * models . User {
2016-01-09 08:28:05 +03:00
user , err := models . GetUserByName ( name )
2015-12-21 15:24:11 +03:00
if err != nil {
if models . IsErrUserNotExist ( err ) {
2018-01-11 00:34:17 +03:00
ctx . NotFound ( "GetUserByName" , nil )
2015-12-21 15:24:11 +03:00
} else {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetUserByName" , err )
2015-12-21 15:24:11 +03:00
}
return nil
}
return user
}
2016-01-09 08:28:05 +03:00
// GetUserByParams returns user whose name is presented in URL paramenter.
2016-03-11 19:56:52 +03:00
func GetUserByParams ( ctx * context . Context ) * models . User {
2016-01-09 08:28:05 +03:00
return GetUserByName ( ctx , ctx . Params ( ":username" ) )
}
2016-11-18 06:03:03 +03:00
// Profile render user's profile page
2016-03-11 19:56:52 +03:00
func Profile ( ctx * context . Context ) {
2015-12-21 15:24:11 +03:00
uname := ctx . Params ( ":username" )
// Special handle for FireFox requests favicon.ico.
if uname == "favicon.ico" {
2015-12-25 13:25:47 +03:00
ctx . ServeFile ( path . Join ( setting . StaticRootPath , "public/img/favicon.png" ) )
2015-12-21 15:24:11 +03:00
return
} else if strings . HasSuffix ( uname , ".png" ) {
ctx . Error ( 404 )
return
}
isShowKeys := false
if strings . HasSuffix ( uname , ".keys" ) {
isShowKeys = true
}
2016-07-24 09:32:46 +03:00
ctxUser := GetUserByName ( ctx , strings . TrimSuffix ( uname , ".keys" ) )
2015-12-21 15:24:11 +03:00
if ctx . Written ( ) {
return
}
// Show SSH keys.
if isShowKeys {
2016-07-24 09:32:46 +03:00
ShowSSHKeys ( ctx , ctxUser . ID )
2015-12-21 15:24:11 +03:00
return
}
2016-07-24 09:32:46 +03:00
if ctxUser . IsOrganization ( ) {
2015-12-21 15:24:11 +03:00
showOrgProfile ( ctx )
return
}
2017-03-20 11:31:08 +03:00
// Show OpenID URIs
openIDs , err := models . GetUserOpenIDs ( ctxUser . ID )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetUserOpenIDs" , err )
2017-03-20 11:31:08 +03:00
return
}
2016-07-24 09:32:46 +03:00
ctx . Data [ "Title" ] = ctxUser . DisplayName ( )
2015-12-21 15:24:11 +03:00
ctx . Data [ "PageIsUserProfile" ] = true
2016-07-24 09:32:46 +03:00
ctx . Data [ "Owner" ] = ctxUser
2017-03-20 11:31:08 +03:00
ctx . Data [ "OpenIDs" ] = openIDs
2018-10-23 05:57:42 +03:00
ctx . Data [ "EnableHeatmap" ] = setting . Service . EnableUserHeatmap
ctx . Data [ "HeatmapUser" ] = ctxUser . Name
2017-02-02 15:32:40 +03:00
showPrivate := ctx . IsSigned && ( ctx . User . IsAdmin || ctx . User . ID == ctxUser . ID )
2016-01-31 00:51:11 +03:00
2017-02-02 15:32:40 +03:00
orgs , err := models . GetOrgsByUserID ( ctxUser . ID , showPrivate )
2016-01-12 05:09:59 +03:00
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetOrgsByUserIDDesc" , err )
2016-01-12 05:09:59 +03:00
return
}
2016-02-07 12:20:58 +03:00
2016-01-12 05:09:59 +03:00
ctx . Data [ "Orgs" ] = orgs
2019-02-18 19:00:27 +03:00
ctx . Data [ "HasOrgsVisible" ] = models . HasOrgsVisible ( orgs , ctx . User )
2015-12-21 15:24:11 +03:00
tab := ctx . Query ( "tab" )
ctx . Data [ "TabName" ] = tab
2017-02-14 10:28:22 +03:00
page := ctx . QueryInt ( "page" )
if page <= 0 {
page = 1
}
2018-09-13 05:33:48 +03:00
topicOnly := ctx . QueryBool ( "topic" )
2017-02-14 10:28:22 +03:00
var (
repos [ ] * models . Repository
count int64
2017-09-22 15:53:21 +03:00
orderBy models . SearchOrderBy
2017-02-14 10:28:22 +03:00
)
ctx . Data [ "SortType" ] = ctx . Query ( "sort" )
switch ctx . Query ( "sort" ) {
case "newest" :
2017-09-22 15:53:21 +03:00
orderBy = models . SearchOrderByNewest
2017-02-14 10:28:22 +03:00
case "oldest" :
2017-09-22 15:53:21 +03:00
orderBy = models . SearchOrderByOldest
2017-02-14 10:28:22 +03:00
case "recentupdate" :
2017-09-22 15:53:21 +03:00
orderBy = models . SearchOrderByRecentUpdated
2017-02-14 10:28:22 +03:00
case "leastupdate" :
2017-09-22 15:53:21 +03:00
orderBy = models . SearchOrderByLeastUpdated
2017-02-14 10:28:22 +03:00
case "reversealphabetically" :
2017-09-22 15:53:21 +03:00
orderBy = models . SearchOrderByAlphabeticallyReverse
2017-02-14 10:28:22 +03:00
case "alphabetically" :
2017-09-22 15:53:21 +03:00
orderBy = models . SearchOrderByAlphabetically
2018-05-24 04:03:42 +03:00
case "moststars" :
orderBy = models . SearchOrderByStarsReverse
case "feweststars" :
orderBy = models . SearchOrderByStars
case "mostforks" :
orderBy = models . SearchOrderByForksReverse
case "fewestforks" :
orderBy = models . SearchOrderByForks
2017-02-14 10:28:22 +03:00
default :
ctx . Data [ "SortType" ] = "recentupdate"
2017-10-05 08:02:43 +03:00
orderBy = models . SearchOrderByRecentUpdated
2017-02-14 10:28:22 +03:00
}
keyword := strings . Trim ( ctx . Query ( "q" ) , " " )
ctx . Data [ "Keyword" ] = keyword
2015-12-21 15:24:11 +03:00
switch tab {
case "activity" :
2017-08-23 04:30:54 +03:00
retrieveFeeds ( ctx , models . GetFeedsOptions { RequestedUser : ctxUser ,
IncludePrivate : showPrivate ,
OnlyPerformedBy : true ,
IncludeDeleted : false ,
} )
2015-12-21 15:24:11 +03:00
if ctx . Written ( ) {
return
}
2016-12-29 17:58:24 +03:00
case "stars" :
2017-02-14 10:28:22 +03:00
ctx . Data [ "PageIsProfileStarList" ] = true
if len ( keyword ) == 0 {
2017-09-22 15:53:21 +03:00
repos , err = ctxUser . GetStarredRepos ( showPrivate , page , setting . UI . User . RepoPagingNum , orderBy . String ( ) )
2017-02-14 10:28:22 +03:00
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetStarredRepos" , err )
2017-02-14 10:28:22 +03:00
return
}
2017-02-07 14:54:16 +03:00
2017-02-14 10:28:22 +03:00
count , err = ctxUser . GetStarredRepoCount ( showPrivate )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetStarredRepoCount" , err )
2017-02-14 10:28:22 +03:00
return
}
} else {
repos , count , err = models . SearchRepositoryByName ( & models . SearchRepoOptions {
2017-10-27 00:16:13 +03:00
Keyword : keyword ,
OwnerID : ctxUser . ID ,
OrderBy : orderBy ,
Private : showPrivate ,
Page : page ,
PageSize : setting . UI . User . RepoPagingNum ,
Starred : true ,
Collaborate : util . OptionalBoolFalse ,
2018-09-13 05:33:48 +03:00
TopicOnly : topicOnly ,
2017-02-14 10:28:22 +03:00
} )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "SearchRepositoryByName" , err )
2017-02-14 10:28:22 +03:00
return
}
2017-02-07 14:54:16 +03:00
}
ctx . Data [ "Repos" ] = repos
2017-02-14 10:28:22 +03:00
ctx . Data [ "Page" ] = paginater . New ( int ( count ) , setting . UI . User . RepoPagingNum , page , 5 )
ctx . Data [ "Total" ] = count
2015-12-21 15:24:11 +03:00
default :
2017-02-04 15:20:20 +03:00
if len ( keyword ) == 0 {
2017-02-06 18:18:36 +03:00
var total int
2017-09-22 15:53:21 +03:00
repos , err = models . GetUserRepositories ( ctxUser . ID , showPrivate , page , setting . UI . User . RepoPagingNum , orderBy . String ( ) )
2017-02-04 15:20:20 +03:00
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetRepositories" , err )
2017-02-04 15:20:20 +03:00
return
}
ctx . Data [ "Repos" ] = repos
2017-02-06 18:18:36 +03:00
if showPrivate {
total = ctxUser . NumRepos
} else {
count , err := models . GetPublicRepositoryCount ( ctxUser )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetPublicRepositoryCount" , err )
2017-02-06 18:18:36 +03:00
return
}
total = int ( count )
}
ctx . Data [ "Page" ] = paginater . New ( total , setting . UI . User . RepoPagingNum , page , 5 )
ctx . Data [ "Total" ] = total
2017-02-04 15:20:20 +03:00
} else {
repos , count , err = models . SearchRepositoryByName ( & models . SearchRepoOptions {
2018-05-21 23:07:34 +03:00
Keyword : keyword ,
OwnerID : ctxUser . ID ,
OrderBy : orderBy ,
Private : showPrivate ,
Page : page ,
IsProfile : true ,
PageSize : setting . UI . User . RepoPagingNum ,
Collaborate : util . OptionalBoolFalse ,
2018-09-13 05:33:48 +03:00
TopicOnly : topicOnly ,
2017-02-04 15:20:20 +03:00
} )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "SearchRepositoryByName" , err )
2017-02-04 15:20:20 +03:00
return
}
ctx . Data [ "Repos" ] = repos
ctx . Data [ "Page" ] = paginater . New ( int ( count ) , setting . UI . User . RepoPagingNum , page , 5 )
ctx . Data [ "Total" ] = count
2015-12-21 15:24:11 +03:00
}
}
2019-02-19 17:11:50 +03:00
ctx . Data [ "ShowUserEmail" ] = len ( ctxUser . Email ) > 0 && ctx . IsSigned && ( ! ctxUser . KeepEmailPrivate || ctxUser . ID == ctx . User . ID )
2017-08-17 12:08:03 +03:00
2016-11-18 06:03:03 +03:00
ctx . HTML ( 200 , tplProfile )
2015-12-21 15:24:11 +03:00
}
2016-11-18 06:03:03 +03:00
// Followers render user's followers page
2016-03-11 19:56:52 +03:00
func Followers ( ctx * context . Context ) {
2015-12-21 15:24:11 +03:00
u := GetUserByParams ( ctx )
if ctx . Written ( ) {
return
}
ctx . Data [ "Title" ] = u . DisplayName ( )
ctx . Data [ "CardsTitle" ] = ctx . Tr ( "user.followers" )
ctx . Data [ "PageIsFollowers" ] = true
ctx . Data [ "Owner" ] = u
2016-11-18 06:03:03 +03:00
repo . RenderUserCards ( ctx , u . NumFollowers , u . GetFollowers , tplFollowers )
2015-12-21 15:24:11 +03:00
}
2016-11-18 06:03:03 +03:00
// Following render user's followering page
2016-03-11 19:56:52 +03:00
func Following ( ctx * context . Context ) {
2015-12-21 15:24:11 +03:00
u := GetUserByParams ( ctx )
if ctx . Written ( ) {
return
}
ctx . Data [ "Title" ] = u . DisplayName ( )
ctx . Data [ "CardsTitle" ] = ctx . Tr ( "user.following" )
ctx . Data [ "PageIsFollowing" ] = true
ctx . Data [ "Owner" ] = u
2016-11-18 06:03:03 +03:00
repo . RenderUserCards ( ctx , u . NumFollowing , u . GetFollowing , tplFollowers )
2015-12-21 15:24:11 +03:00
}
2016-11-18 06:03:03 +03:00
// Action response for follow/unfollow user request
2016-03-11 19:56:52 +03:00
func Action ( ctx * context . Context ) {
2015-12-21 15:24:11 +03:00
u := GetUserByParams ( ctx )
if ctx . Written ( ) {
return
}
var err error
switch ctx . Params ( ":action" ) {
case "follow" :
2016-07-23 20:08:22 +03:00
err = models . FollowUser ( ctx . User . ID , u . ID )
2015-12-21 15:24:11 +03:00
case "unfollow" :
2016-07-23 20:08:22 +03:00
err = models . UnfollowUser ( ctx . User . ID , u . ID )
2015-12-21 15:24:11 +03:00
}
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( fmt . Sprintf ( "Action (%s)" , ctx . Params ( ":action" ) ) , err )
2015-12-21 15:24:11 +03:00
return
}
2018-03-16 00:13:34 +03:00
ctx . RedirectToFirst ( ctx . Query ( "redirect_to" ) , u . HomeLink ( ) )
2015-12-21 15:24:11 +03:00
}