2014-04-13 09:57:42 +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-23 10:33:47 +03:00
"bytes"
2014-04-13 09:57:42 +04:00
"fmt"
2014-05-07 20:09:30 +04:00
"github.com/Unknwon/com"
2015-08-25 17:58:34 +03:00
"github.com/Unknwon/paginater"
2014-04-13 09:57:42 +04:00
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-01-25 05:43:02 +03:00
"code.gitea.io/gitea/modules/util"
2014-04-13 09:57:42 +04:00
)
2014-06-23 07:11:12 +04:00
const (
2016-11-18 06:03:03 +03:00
tplDashborad base . TplName = "user/dashboard/dashboard"
tplIssues base . TplName = "user/dashboard/issues"
tplProfile base . TplName = "user/profile"
tplOrgHome base . TplName = "org/home"
2014-06-23 07:11:12 +04:00
)
2016-07-23 20:08:22 +03:00
// getDashboardContextUser finds out dashboard is viewing as which context user.
2016-03-11 19:56:52 +03:00
func getDashboardContextUser ( ctx * context . Context ) * models . User {
2015-08-25 17:58:34 +03:00
ctxUser := ctx . User
2014-07-27 07:53:16 +04:00
orgName := ctx . Params ( ":org" )
if len ( orgName ) > 0 {
// Organization.
org , err := models . GetUserByName ( orgName )
if err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
2014-07-27 07:53:16 +04:00
ctx . Handle ( 404 , "GetUserByName" , err )
} else {
ctx . Handle ( 500 , "GetUserByName" , err )
}
2015-08-25 17:58:34 +03:00
return nil
2014-07-27 07:53:16 +04:00
}
ctxUser = org
2015-08-25 17:58:34 +03:00
}
ctx . Data [ "ContextUser" ] = ctxUser
2015-12-17 10:28:47 +03:00
if err := ctx . User . GetOrganizations ( true ) ; err != nil {
2015-08-25 17:58:34 +03:00
ctx . Handle ( 500 , "GetOrganizations" , err )
return nil
}
ctx . Data [ "Orgs" ] = ctx . User . Orgs
return ctxUser
}
2016-07-23 20:08:22 +03:00
// retrieveFeeds loads feeds from database by given context user.
// The user could be organization so it is not always the logged in user,
// which is why we have to explicitly pass the context user ID.
2016-07-24 09:32:46 +03:00
func retrieveFeeds ( ctx * context . Context , ctxUser * models . User , userID , offset int64 , isProfile bool ) {
actions , err := models . GetFeeds ( ctxUser , userID , offset , isProfile )
2015-11-22 09:32:09 +03:00
if err != nil {
ctx . Handle ( 500 , "GetFeeds" , err )
return
}
// Check access of private repositories.
feeds := make ( [ ] * models . Action , 0 , len ( actions ) )
2017-02-03 08:27:10 +03:00
unameAvatars := map [ string ] string {
ctxUser . Name : ctxUser . RelAvatarLink ( ) ,
}
2015-11-22 09:32:09 +03:00
for _ , act := range actions {
// Cache results to reduce queries.
_ , ok := unameAvatars [ act . ActUserName ]
if ! ok {
u , err := models . GetUserByName ( act . ActUserName )
if err != nil {
if models . IsErrUserNotExist ( err ) {
continue
}
ctx . Handle ( 500 , "GetUserByName" , err )
return
}
2016-08-05 22:12:54 +03:00
unameAvatars [ act . ActUserName ] = u . RelAvatarLink ( )
2015-11-22 09:32:09 +03:00
}
act . ActAvatar = unameAvatars [ act . ActUserName ]
feeds = append ( feeds , act )
}
ctx . Data [ "Feeds" ] = feeds
}
2016-11-18 06:03:03 +03:00
// Dashboard render the dashborad page
2016-03-11 19:56:52 +03:00
func Dashboard ( ctx * context . Context ) {
2016-03-10 07:56:03 +03:00
ctxUser := getDashboardContextUser ( ctx )
2015-08-25 17:58:34 +03:00
if ctx . Written ( ) {
return
}
2016-07-23 20:08:22 +03:00
ctx . Data [ "Title" ] = ctxUser . DisplayName ( ) + " - " + ctx . Tr ( "dashboard" )
ctx . Data [ "PageIsDashboard" ] = true
ctx . Data [ "PageIsNews" ] = true
// Only user can have collaborative repositories.
2015-08-25 17:58:34 +03:00
if ! ctxUser . IsOrganization ( ) {
2016-07-24 09:32:46 +03:00
collaborateRepos , err := ctx . User . GetAccessibleRepositories ( setting . UI . User . RepoPagingNum )
2014-07-27 07:53:16 +04:00
if err != nil {
2015-01-23 10:54:16 +03:00
ctx . Handle ( 500 , "GetAccessibleRepositories" , err )
2014-07-27 07:53:16 +04:00
return
2016-07-24 09:32:46 +03:00
} else if err = models . RepositoryList ( collaborateRepos ) . LoadAttributes ( ) ; err != nil {
ctx . Handle ( 500 , "RepositoryList.LoadAttributes" , err )
return
2014-07-27 07:53:16 +04:00
}
2015-11-14 01:37:02 +03:00
ctx . Data [ "CollaborativeRepos" ] = collaborateRepos
2014-07-27 07:53:16 +04:00
}
2014-06-25 08:44:48 +04:00
2016-07-24 09:32:46 +03:00
var err error
var repos , mirrors [ ] * models . Repository
2016-02-02 22:29:35 +03:00
if ctxUser . IsOrganization ( ) {
2017-01-25 18:41:38 +03:00
env , err := ctxUser . AccessibleReposEnv ( ctx . User . ID )
2016-07-24 09:32:46 +03:00
if err != nil {
2017-01-25 18:41:38 +03:00
ctx . Handle ( 500 , "AccessibleReposEnv" , err )
return
}
repos , err = env . Repos ( 1 , setting . UI . User . RepoPagingNum )
if err != nil {
ctx . Handle ( 500 , "env.Repos" , err )
2016-02-02 22:29:35 +03:00
return
}
2016-07-24 09:32:46 +03:00
2017-01-25 18:41:38 +03:00
mirrors , err = env . MirrorRepos ( )
2016-02-02 22:29:35 +03:00
if err != nil {
2017-01-25 18:41:38 +03:00
ctx . Handle ( 500 , "env.MirrorRepos" , err )
2016-07-24 09:32:46 +03:00
return
}
} else {
if err = ctxUser . GetRepositories ( 1 , setting . UI . User . RepoPagingNum ) ; err != nil {
2016-02-02 22:29:35 +03:00
ctx . Handle ( 500 , "GetRepositories" , err )
return
}
2016-07-24 09:32:46 +03:00
repos = ctxUser . Repos
mirrors , err = ctxUser . GetMirrorRepositories ( )
if err != nil {
ctx . Handle ( 500 , "GetMirrorRepositories" , err )
return
}
2014-04-13 09:57:42 +04:00
}
2014-07-26 08:24:27 +04:00
ctx . Data [ "Repos" ] = repos
2016-07-24 09:32:46 +03:00
ctx . Data [ "MaxShowRepoNum" ] = setting . UI . User . RepoPagingNum
2014-04-13 09:57:42 +04:00
2016-07-24 09:32:46 +03:00
if err := models . MirrorRepositoryList ( mirrors ) . LoadAttributes ( ) ; err != nil {
ctx . Handle ( 500 , "MirrorRepositoryList.LoadAttributes" , err )
return
2014-07-26 10:28:04 +04:00
}
2014-07-27 07:53:16 +04:00
ctx . Data [ "MirrorCount" ] = len ( mirrors )
ctx . Data [ "Mirrors" ] = mirrors
2014-05-12 23:14:22 +04:00
2016-07-24 09:32:46 +03:00
retrieveFeeds ( ctx , ctxUser , ctx . User . ID , 0 , false )
2015-11-22 09:32:09 +03:00
if ctx . Written ( ) {
2014-04-13 09:57:42 +04:00
return
}
2016-11-18 06:03:03 +03:00
ctx . HTML ( 200 , tplDashborad )
2014-04-13 09:57:42 +04:00
}
2016-11-18 06:03:03 +03:00
// Issues render the user issues page
2016-03-11 19:56:52 +03:00
func Issues ( ctx * context . Context ) {
2015-09-02 23:18:09 +03:00
isPullList := ctx . Params ( ":type" ) == "pulls"
if isPullList {
ctx . Data [ "Title" ] = ctx . Tr ( "pull_requests" )
ctx . Data [ "PageIsPulls" ] = true
} else {
ctx . Data [ "Title" ] = ctx . Tr ( "issues" )
ctx . Data [ "PageIsIssues" ] = true
}
2015-08-25 17:58:34 +03:00
ctxUser := getDashboardContextUser ( ctx )
if ctx . Written ( ) {
return
}
// Organization does not have view type and filter mode.
var (
viewType string
2015-11-04 20:50:02 +03:00
sortType = ctx . Query ( "sort" )
2016-11-07 19:24:59 +03:00
filterMode = models . FilterModeAll
2015-08-25 17:58:34 +03:00
)
2017-02-14 17:15:18 +03:00
2015-08-25 17:58:34 +03:00
if ctxUser . IsOrganization ( ) {
viewType = "all"
} else {
viewType = ctx . Query ( "type" )
2017-02-14 17:15:18 +03:00
types := [ ] string { "all" , "assigned" , "created_by" }
2015-08-25 17:58:34 +03:00
if ! com . IsSliceContainsStr ( types , viewType ) {
viewType = "all"
}
switch viewType {
2017-02-14 17:15:18 +03:00
case "all" :
filterMode = models . FilterModeAll
2015-08-25 17:58:34 +03:00
case "assigned" :
2016-11-07 19:24:59 +03:00
filterMode = models . FilterModeAssign
2015-08-25 17:58:34 +03:00
case "created_by" :
2016-11-07 19:24:59 +03:00
filterMode = models . FilterModeCreate
2015-08-25 17:58:34 +03:00
}
}
2017-02-14 17:15:18 +03:00
page := ctx . QueryInt ( "page" )
if page <= 1 {
page = 1
}
2015-08-25 17:58:34 +03:00
repoID := ctx . QueryInt64 ( "repo" )
isShowClosed := ctx . Query ( "state" ) == "closed"
// Get repositories.
2016-07-24 09:32:46 +03:00
var err error
2017-02-17 03:58:19 +03:00
var userRepoIDs [ ] int64
2016-01-31 23:12:03 +03:00
if ctxUser . IsOrganization ( ) {
2017-01-25 18:41:38 +03:00
env , err := ctxUser . AccessibleReposEnv ( ctx . User . ID )
if err != nil {
ctx . Handle ( 500 , "AccessibleReposEnv" , err )
return
}
2017-02-17 03:58:19 +03:00
userRepoIDs , err = env . RepoIDs ( 1 , ctxUser . NumRepos )
2016-07-24 09:32:46 +03:00
if err != nil {
2017-02-17 03:58:19 +03:00
ctx . Handle ( 500 , "env.RepoIDs" , err )
2016-01-31 23:12:03 +03:00
return
}
} else {
2017-02-17 03:58:19 +03:00
userRepoIDs , err = ctxUser . GetAccessRepoIDs ( )
if err != nil {
ctx . Handle ( 500 , "ctxUser.GetAccessRepoIDs" , err )
2016-01-31 23:12:03 +03:00
return
}
2017-02-17 03:58:19 +03:00
}
2015-08-25 17:58:34 +03:00
2017-02-17 03:58:19 +03:00
if len ( userRepoIDs ) <= 0 {
userRepoIDs = [ ] int64 { - 1 }
2017-02-14 17:15:18 +03:00
}
var issues [ ] * models . Issue
switch filterMode {
case models . FilterModeAll :
// Get all issues from repositories from this user.
issues , err = models . Issues ( & models . IssuesOptions {
RepoIDs : userRepoIDs ,
RepoID : repoID ,
Page : page ,
IsClosed : util . OptionalBoolOf ( isShowClosed ) ,
IsPull : util . OptionalBoolOf ( isPullList ) ,
SortType : sortType ,
} )
case models . FilterModeAssign :
// Get all issues assigned to this user.
issues , err = models . Issues ( & models . IssuesOptions {
RepoID : repoID ,
AssigneeID : ctxUser . ID ,
Page : page ,
IsClosed : util . OptionalBoolOf ( isShowClosed ) ,
IsPull : util . OptionalBoolOf ( isPullList ) ,
SortType : sortType ,
} )
case models . FilterModeCreate :
// Get all issues created by this user.
issues , err = models . Issues ( & models . IssuesOptions {
RepoID : repoID ,
PosterID : ctxUser . ID ,
Page : page ,
IsClosed : util . OptionalBoolOf ( isShowClosed ) ,
IsPull : util . OptionalBoolOf ( isPullList ) ,
SortType : sortType ,
} )
case models . FilterModeMention :
// Get all issues created by this user.
issues , err = models . Issues ( & models . IssuesOptions {
RepoID : repoID ,
MentionedID : ctxUser . ID ,
Page : page ,
IsClosed : util . OptionalBoolOf ( isShowClosed ) ,
IsPull : util . OptionalBoolOf ( isPullList ) ,
SortType : sortType ,
} )
}
if err != nil {
ctx . Handle ( 500 , "Issues" , err )
return
}
2017-02-17 03:58:19 +03:00
showRepos , err := models . IssueList ( issues ) . LoadRepositories ( )
if err != nil {
ctx . Handle ( 500 , "LoadRepositories" , fmt . Errorf ( "%v" , err ) )
return
}
2015-09-02 23:18:09 +03:00
2017-02-14 17:15:18 +03:00
if repoID > 0 {
2017-02-17 03:58:19 +03:00
var theRepo * models . Repository
for _ , repo := range showRepos {
if repo . ID == repoID {
theRepo = repo
break
}
2015-09-02 23:18:09 +03:00
}
2015-08-25 17:58:34 +03:00
2017-02-17 03:58:19 +03:00
if theRepo == nil {
theRepo , err = models . GetRepositoryByID ( repoID )
if err != nil {
ctx . Handle ( 500 , "GetRepositoryByID" , fmt . Errorf ( "[#%d]%v" , repoID , err ) )
return
}
showRepos = append ( showRepos , theRepo )
2015-08-25 17:58:34 +03:00
}
2017-02-14 17:15:18 +03:00
// Check if user has access to given repository.
2017-02-17 03:58:19 +03:00
if ! theRepo . IsOwnedBy ( ctxUser . ID ) && ! theRepo . HasAccess ( ctxUser ) {
2017-02-14 17:15:18 +03:00
ctx . Handle ( 404 , "Issues" , fmt . Errorf ( "#%d" , repoID ) )
return
2015-08-25 17:58:34 +03:00
}
2016-12-23 03:26:01 +03:00
}
2015-08-25 17:58:34 +03:00
2017-02-17 03:58:19 +03:00
err = models . RepositoryList ( showRepos ) . LoadAttributes ( )
if err != nil {
ctx . Handle ( 500 , "LoadAttributes" , fmt . Errorf ( "%v" , err ) )
return
2015-08-25 18:22:05 +03:00
}
2017-02-14 17:15:18 +03:00
issueStats := models . GetUserIssueStats ( repoID , ctxUser . ID , userRepoIDs , filterMode , isPullList )
2015-08-25 18:22:05 +03:00
var total int
if ! isShowClosed {
total = int ( issueStats . OpenCount )
} else {
total = int ( issueStats . ClosedCount )
}
2015-08-25 17:58:34 +03:00
ctx . Data [ "Issues" ] = issues
2017-02-14 17:15:18 +03:00
ctx . Data [ "Repos" ] = showRepos
ctx . Data [ "Page" ] = paginater . New ( total , setting . UI . IssuePagingNum , page , 5 )
2015-08-25 17:58:34 +03:00
ctx . Data [ "IssueStats" ] = issueStats
ctx . Data [ "ViewType" ] = viewType
2015-11-04 20:50:02 +03:00
ctx . Data [ "SortType" ] = sortType
2015-08-25 17:58:34 +03:00
ctx . Data [ "RepoID" ] = repoID
ctx . Data [ "IsShowClosed" ] = isShowClosed
2017-02-14 17:15:18 +03:00
2015-08-25 17:58:34 +03:00
if isShowClosed {
ctx . Data [ "State" ] = "closed"
} else {
ctx . Data [ "State" ] = "open"
}
2016-11-18 06:03:03 +03:00
ctx . HTML ( 200 , tplIssues )
2015-08-25 17:58:34 +03:00
}
2016-11-27 14:59:12 +03:00
// ShowSSHKeys output all the ssh keys of user by uid
2016-03-11 19:56:52 +03:00
func ShowSSHKeys ( ctx * context . Context , uid int64 ) {
2014-11-23 10:33:47 +03:00
keys , err := models . ListPublicKeys ( uid )
if err != nil {
ctx . Handle ( 500 , "ListPublicKeys" , err )
return
}
var buf bytes . Buffer
for i := range keys {
buf . WriteString ( keys [ i ] . OmitEmail ( ) )
2015-06-08 10:40:38 +03:00
buf . WriteString ( "\n" )
2014-11-23 10:33:47 +03:00
}
2015-10-16 04:28:12 +03:00
ctx . PlainText ( 200 , buf . Bytes ( ) )
2014-11-23 10:33:47 +03:00
}
2016-03-11 19:56:52 +03:00
func showOrgProfile ( ctx * context . Context ) {
2015-11-25 03:14:00 +03:00
ctx . SetParams ( ":org" , ctx . Params ( ":username" ) )
2016-03-11 19:56:52 +03:00
context . HandleOrgAssignment ( ctx )
2015-11-25 03:14:00 +03:00
if ctx . Written ( ) {
return
}
org := ctx . Org . Organization
2017-04-15 05:02:46 +03:00
ctx . Data [ "Title" ] = org . DisplayName ( )
2015-11-25 03:14:00 +03:00
2016-07-24 09:32:46 +03:00
page := ctx . QueryInt ( "page" )
if page <= 0 {
page = 1
}
var (
repos [ ] * models . Repository
count int64
err error
)
if ctx . IsSigned && ! ctx . User . IsAdmin {
2017-01-25 18:41:38 +03:00
env , err := org . AccessibleReposEnv ( ctx . User . ID )
if err != nil {
ctx . Handle ( 500 , "AccessibleReposEnv" , err )
return
}
repos , err = env . Repos ( page , setting . UI . User . RepoPagingNum )
if err != nil {
ctx . Handle ( 500 , "env.Repos" , err )
return
}
count , err = env . CountRepos ( )
2016-07-24 09:32:46 +03:00
if err != nil {
2017-01-25 18:41:38 +03:00
ctx . Handle ( 500 , "env.CountRepos" , err )
2016-07-24 09:32:46 +03:00
return
2016-01-31 21:13:39 +03:00
}
2016-07-24 09:32:46 +03:00
ctx . Data [ "Repos" ] = repos
2016-01-31 21:13:39 +03:00
} else {
2016-07-24 09:32:46 +03:00
showPrivate := ctx . IsSigned && ctx . User . IsAdmin
2017-02-04 15:20:20 +03:00
repos , err = models . GetUserRepositories ( org . ID , showPrivate , page , setting . UI . User . RepoPagingNum , "" )
2016-02-04 20:13:56 +03:00
if err != nil {
2016-01-31 21:13:39 +03:00
ctx . Handle ( 500 , "GetRepositories" , err )
return
}
2016-02-04 20:13:56 +03:00
ctx . Data [ "Repos" ] = repos
2016-07-24 09:32:46 +03:00
count = models . CountUserRepositories ( org . ID , showPrivate )
2015-11-25 03:14:00 +03:00
}
2016-07-24 09:32:46 +03:00
ctx . Data [ "Page" ] = paginater . New ( int ( count ) , setting . UI . User . RepoPagingNum , page , 5 )
2015-11-25 03:14:00 +03:00
2016-01-31 13:46:04 +03:00
if err := org . GetMembers ( ) ; err != nil {
2015-11-25 03:14:00 +03:00
ctx . Handle ( 500 , "GetMembers" , err )
return
}
ctx . Data [ "Members" ] = org . Members
2016-01-31 22:08:20 +03:00
ctx . Data [ "Teams" ] = org . Teams
2015-11-25 03:14:00 +03:00
2016-11-18 06:03:03 +03:00
ctx . HTML ( 200 , tplOrgHome )
2015-11-25 03:14:00 +03:00
}
2016-11-18 06:03:03 +03:00
// Email2User show user page via email
2016-03-11 19:56:52 +03:00
func Email2User ( ctx * context . Context ) {
2014-04-13 09:57:42 +04:00
u , err := models . GetUserByEmail ( ctx . Query ( "email" ) )
if err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
ctx . Handle ( 404 , "GetUserByEmail" , err )
2014-04-13 09:57:42 +04:00
} else {
2015-08-05 06:14:17 +03:00
ctx . Handle ( 500 , "GetUserByEmail" , err )
2014-04-13 09:57:42 +04:00
}
return
}
2016-11-27 13:14:25 +03:00
ctx . Redirect ( setting . AppSubURL + "/user/" + u . Name )
2014-04-13 09:57:42 +04:00
}