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-11-23 10:33:47 +03:00
"strings"
2014-04-13 09:57:42 +04:00
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
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/middleware"
2014-09-14 21:35:22 +04:00
"github.com/gogits/gogs/modules/setting"
2014-04-13 09:57:42 +04:00
)
2014-06-23 07:11:12 +04:00
const (
2014-07-26 08:24:27 +04:00
DASHBOARD base . TplName = "user/dashboard/dashboard"
2015-08-25 17:58:34 +03:00
ISSUES base . TplName = "user/dashboard/issues"
2014-06-23 07:11:12 +04:00
STARS base . TplName = "user/stars"
2014-07-26 08:24:27 +04:00
PROFILE base . TplName = "user/profile"
2014-06-23 07:11:12 +04:00
)
2015-08-25 17:58:34 +03:00
func getDashboardContextUser ( ctx * middleware . Context ) * models . User {
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
if err := ctx . User . GetOrganizations ( ) ; err != nil {
ctx . Handle ( 500 , "GetOrganizations" , err )
return nil
}
ctx . Data [ "Orgs" ] = ctx . User . Orgs
return ctxUser
}
func Dashboard ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "dashboard" )
ctx . Data [ "PageIsDashboard" ] = true
ctx . Data [ "PageIsNews" ] = true
ctxUser := getDashboardContextUser ( ctx )
if ctx . Written ( ) {
return
}
if ! ctxUser . IsOrganization ( ) {
2015-11-14 01:37:02 +03:00
collaborateRepos , err := ctx . User . GetAccessibleRepositories ( )
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
}
2015-01-23 10:54:16 +03:00
2015-11-14 01:37:02 +03:00
for i := range collaborateRepos {
if err = collaborateRepos [ i ] . GetOwner ( ) ; err != nil {
ctx . Handle ( 500 , "GetOwner: " + collaborateRepos [ i ] . Name , err )
return
}
2015-01-23 10:54:16 +03:00
}
2015-11-14 01:37:02 +03:00
ctx . Data [ "CollaborateCount" ] = len ( collaborateRepos )
ctx . Data [ "CollaborativeRepos" ] = collaborateRepos
2014-07-27 07:53:16 +04:00
}
2014-06-25 08:44:48 +04:00
2014-07-27 07:53:16 +04:00
repos , err := models . GetRepositories ( ctxUser . Id , true )
2014-04-13 09:57:42 +04:00
if err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "GetRepositories" , err )
2014-04-13 09:57:42 +04:00
return
}
2014-07-26 08:24:27 +04:00
ctx . Data [ "Repos" ] = repos
2014-04-13 09:57:42 +04:00
2014-07-27 07:53:16 +04:00
// Get mirror repositories.
2015-11-14 01:37:02 +03:00
mirrors := make ( [ ] * models . Repository , 0 , 5 )
2014-07-27 07:53:16 +04:00
for _ , repo := range repos {
if repo . IsMirror {
2014-08-11 07:11:18 +04:00
if err = repo . GetMirror ( ) ; err != nil {
ctx . Handle ( 500 , "GetMirror: " + repo . Name , err )
return
}
2014-07-27 07:53:16 +04:00
mirrors = append ( mirrors , repo )
}
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
2014-07-27 07:53:16 +04:00
// Get feeds.
actions , err := models . GetFeeds ( ctxUser . Id , 0 , false )
2014-04-13 09:57:42 +04:00
if err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "GetFeeds" , err )
2014-04-13 09:57:42 +04:00
return
}
2014-05-09 03:17:43 +04:00
2014-05-24 23:28:31 +04:00
// Check access of private repositories.
2014-05-09 03:17:43 +04:00
feeds := make ( [ ] * models . Action , 0 , len ( actions ) )
2015-11-14 00:43:43 +03:00
unameAvatars := make ( map [ string ] string )
2014-05-09 03:17:43 +04:00
for _ , act := range actions {
if act . IsPrivate {
2015-02-16 14:16:24 +03:00
// This prevents having to retrieve the repository for each action
2015-08-08 17:43:14 +03:00
repo := & models . Repository { ID : act . RepoID , IsPrivate : true }
2015-02-18 09:59:22 +03:00
if act . RepoUserName != ctx . User . LowerName {
if has , _ := models . HasAccess ( ctx . User , repo , models . ACCESS_MODE_READ ) ; ! has {
continue
}
2014-05-09 03:17:43 +04:00
}
2015-02-18 09:59:22 +03:00
2014-05-09 03:17:43 +04:00
}
2015-11-14 00:43:43 +03:00
// 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
2014-12-18 11:26:09 +03:00
}
2015-11-14 00:43:43 +03:00
unameAvatars [ act . ActUserName ] = u . AvatarLink ( )
2014-11-21 18:58:08 +03:00
}
2015-11-14 00:43:43 +03:00
act . ActAvatar = unameAvatars [ act . ActUserName ]
2014-05-09 03:17:43 +04:00
feeds = append ( feeds , act )
}
2014-04-13 09:57:42 +04:00
ctx . Data [ "Feeds" ] = feeds
2014-06-23 07:11:12 +04:00
ctx . HTML ( 200 , DASHBOARD )
2014-04-13 09:57:42 +04:00
}
2015-08-25 17:58:34 +03:00
func Issues ( ctx * middleware . 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" )
2015-08-25 17:58:34 +03:00
filterMode = models . FM_ALL
assigneeID int64
posterID int64
)
if ctxUser . IsOrganization ( ) {
viewType = "all"
} else {
viewType = ctx . Query ( "type" )
types := [ ] string { "assigned" , "created_by" }
if ! com . IsSliceContainsStr ( types , viewType ) {
viewType = "all"
}
switch viewType {
case "assigned" :
filterMode = models . FM_ASSIGN
assigneeID = ctxUser . Id
case "created_by" :
filterMode = models . FM_CREATE
posterID = ctxUser . Id
}
}
repoID := ctx . QueryInt64 ( "repo" )
isShowClosed := ctx . Query ( "state" ) == "closed"
// Get repositories.
repos , err := models . GetRepositories ( ctxUser . Id , true )
if err != nil {
ctx . Handle ( 500 , "GetRepositories" , err )
return
}
2015-08-25 18:22:05 +03:00
allCount := 0
2015-08-25 17:58:34 +03:00
repoIDs := make ( [ ] int64 , 0 , len ( repos ) )
showRepos := make ( [ ] * models . Repository , 0 , len ( repos ) )
for _ , repo := range repos {
2015-09-02 23:18:09 +03:00
if ( isPullList && repo . NumPulls == 0 ) ||
( ! isPullList && repo . NumIssues == 0 ) {
2015-08-25 17:58:34 +03:00
continue
}
repoIDs = append ( repoIDs , repo . ID )
2015-09-02 23:18:09 +03:00
if isPullList {
allCount += repo . NumOpenPulls
repo . NumOpenIssues = repo . NumOpenPulls
repo . NumClosedIssues = repo . NumClosedPulls
} else {
allCount += repo . NumOpenIssues
}
2015-08-25 17:58:34 +03:00
2015-08-25 18:22:05 +03:00
if filterMode != models . FM_ALL {
2015-08-25 17:58:34 +03:00
// Calculate repository issue count with filter mode.
2015-09-02 23:18:09 +03:00
numOpen , numClosed := repo . IssueStats ( ctxUser . Id , filterMode , isPullList )
2015-08-25 17:58:34 +03:00
repo . NumOpenIssues , repo . NumClosedIssues = int ( numOpen ) , int ( numClosed )
}
if repo . ID == repoID ||
( isShowClosed && repo . NumClosedIssues > 0 ) ||
( ! isShowClosed && repo . NumOpenIssues > 0 ) {
showRepos = append ( showRepos , repo )
}
}
ctx . Data [ "Repos" ] = showRepos
2015-09-02 23:18:09 +03:00
issueStats := models . GetUserIssueStats ( repoID , ctxUser . Id , repoIDs , filterMode , isPullList )
2015-08-25 18:22:05 +03:00
issueStats . AllCount = int64 ( allCount )
page := ctx . QueryInt ( "page" )
if page <= 1 {
page = 1
}
var total int
if ! isShowClosed {
total = int ( issueStats . OpenCount )
} else {
total = int ( issueStats . ClosedCount )
}
ctx . Data [ "Page" ] = paginater . New ( total , setting . IssuePagingNum , page , 5 )
2015-08-25 17:58:34 +03:00
// Get issues.
2015-09-02 23:18:09 +03:00
issues , err := models . Issues ( & models . IssuesOptions {
UserID : ctxUser . Id ,
AssigneeID : assigneeID ,
RepoID : repoID ,
PosterID : posterID ,
RepoIDs : repoIDs ,
Page : page ,
IsClosed : isShowClosed ,
IsPull : isPullList ,
2015-11-04 20:50:02 +03:00
SortType : sortType ,
2015-09-02 23:18:09 +03:00
} )
2015-08-25 17:58:34 +03:00
if err != nil {
ctx . Handle ( 500 , "Issues: %v" , err )
return
}
// Get posters and repository.
for i := range issues {
issues [ i ] . Repo , err = models . GetRepositoryByID ( issues [ i ] . RepoID )
if err != nil {
ctx . Handle ( 500 , "GetRepositoryByID" , fmt . Errorf ( "[#%d]%v" , issues [ i ] . ID , err ) )
return
}
if err = issues [ i ] . Repo . GetOwner ( ) ; err != nil {
ctx . Handle ( 500 , "GetOwner" , fmt . Errorf ( "[#%d]%v" , issues [ i ] . ID , err ) )
return
}
if err = issues [ i ] . GetPoster ( ) ; err != nil {
ctx . Handle ( 500 , "GetPoster" , fmt . Errorf ( "[#%d]%v" , issues [ i ] . ID , err ) )
return
}
}
ctx . Data [ "Issues" ] = issues
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
if isShowClosed {
ctx . Data [ "State" ] = "closed"
} else {
ctx . Data [ "State" ] = "open"
}
ctx . HTML ( 200 , ISSUES )
}
2014-11-23 10:33:47 +03:00
func ShowSSHKeys ( ctx * middleware . Context , uid int64 ) {
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
}
2014-07-26 08:24:27 +04:00
func Profile ( ctx * middleware . Context ) {
2014-04-13 09:57:42 +04:00
ctx . Data [ "Title" ] = "Profile"
2014-05-24 23:28:31 +04:00
ctx . Data [ "PageIsUserProfile" ] = true
2014-04-13 09:57:42 +04:00
2014-08-07 01:21:24 +04:00
uname := ctx . Params ( ":username" )
// Special handle for FireFox requests favicon.ico.
if uname == "favicon.ico" {
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/img/favicon.png" )
2014-08-07 01:21:24 +04:00
return
}
2014-11-23 10:33:47 +03:00
isShowKeys := false
if strings . HasSuffix ( uname , ".keys" ) {
isShowKeys = true
uname = strings . TrimSuffix ( uname , ".keys" )
}
2014-08-07 01:21:24 +04:00
u , err := models . GetUserByName ( uname )
2014-04-13 09:57:42 +04:00
if err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
2014-08-07 01:21:24 +04:00
ctx . Handle ( 404 , "GetUserByName" , err )
2014-05-09 04:00:07 +04:00
} else {
2014-08-07 01:21:24 +04:00
ctx . Handle ( 500 , "GetUserByName" , err )
2014-05-09 04:00:07 +04:00
}
2014-04-13 09:57:42 +04:00
return
}
2014-06-28 23:43:25 +04:00
2014-11-23 10:33:47 +03:00
// Show SSH keys.
if isShowKeys {
ShowSSHKeys ( ctx , u . Id )
return
}
2014-06-28 23:43:25 +04:00
if u . IsOrganization ( ) {
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/org/" + u . Name )
2014-06-28 23:43:25 +04:00
return
}
2014-06-24 03:16:09 +04:00
ctx . Data [ "Owner" ] = u
2014-04-13 09:57:42 +04:00
tab := ctx . Query ( "tab" )
ctx . Data [ "TabName" ] = tab
switch tab {
case "activity" :
2015-11-16 19:43:23 +03:00
actions , err := models . GetFeeds ( u . Id , 0 , true )
2014-04-13 09:57:42 +04:00
if err != nil {
2014-08-07 01:21:24 +04:00
ctx . Handle ( 500 , "GetFeeds" , err )
2014-04-13 09:57:42 +04:00
return
}
2014-11-21 19:08:24 +03:00
feeds := make ( [ ] * models . Action , 0 , len ( actions ) )
for _ , act := range actions {
2014-12-17 04:47:10 +03:00
if act . IsPrivate {
if ! ctx . IsSigned {
continue
}
2015-02-16 14:16:24 +03:00
// This prevents having to retrieve the repository for each action
2015-08-08 17:43:14 +03:00
repo := & models . Repository { ID : act . RepoID , IsPrivate : true }
2015-02-18 09:59:22 +03:00
if act . RepoUserName != ctx . User . LowerName {
if has , _ := models . HasAccess ( ctx . User , repo , models . ACCESS_MODE_READ ) ; ! has {
continue
}
2014-12-17 04:47:10 +03:00
}
2015-02-18 09:59:22 +03:00
2014-12-17 04:47:10 +03:00
}
2014-11-21 19:08:24 +03:00
// FIXME: cache results?
u , err := models . GetUserByName ( act . ActUserName )
if err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
2014-12-18 11:37:31 +03:00
continue
}
2014-11-21 19:08:24 +03:00
ctx . Handle ( 500 , "GetUserByName" , err )
return
}
act . ActAvatar = u . AvatarLink ( )
feeds = append ( feeds , act )
}
ctx . Data [ "Feeds" ] = feeds
2014-04-13 09:57:42 +04:00
default :
2014-06-24 03:16:09 +04:00
ctx . Data [ "Repos" ] , err = models . GetRepositories ( u . Id , ctx . IsSigned && ctx . User . Id == u . Id )
2014-04-13 09:57:42 +04:00
if err != nil {
2014-08-07 01:21:24 +04:00
ctx . Handle ( 500 , "GetRepositories" , err )
2014-04-13 09:57:42 +04:00
return
}
}
2014-06-23 07:11:12 +04:00
ctx . HTML ( 200 , PROFILE )
2014-04-13 09:57:42 +04:00
}
func Email2User ( ctx * middleware . Context ) {
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
}
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/" + u . Name )
2014-04-13 09:57:42 +04:00
}