Both are possible on explore and admin paneltags/v0.9.99
@@ -3,7 +3,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra | |||
![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true) | |||
##### Current version: 0.9.5 | |||
##### Current version: 0.9.6 | |||
| Web | UI | Preview | | |||
|:-------------:|:-------:|:-------:| |
@@ -193,7 +193,10 @@ func runWeb(ctx *cli.Context) { | |||
// Especially some AJAX requests, we can reduce middleware number to improve performance. | |||
// Routers. | |||
m.Get("/", ignSignIn, routers.Home) | |||
m.Get("/explore", ignSignIn, routers.Explore) | |||
m.Group("/explore", func() { | |||
m.Get("/repos", routers.ExploreRepos) | |||
m.Get("/users", routers.ExploreUsers) | |||
}, ignSignIn) | |||
m.Combo("/install", routers.InstallInit).Get(routers.Install). | |||
Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost) | |||
m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues) |
@@ -44,13 +44,6 @@ issues = Issues | |||
cancel = Cancel | |||
[search] | |||
search = Search... | |||
repository = Repository | |||
user = User | |||
issue = Issue | |||
code = Code | |||
[install] | |||
install = Installation | |||
title = Install Steps For First-time Run | |||
@@ -140,6 +133,8 @@ issues.in_your_repos = In your repositories | |||
[explore] | |||
repos = Repositories | |||
users = Users | |||
search = Search | |||
[auth] | |||
create_new_account = Create New Account |
@@ -17,7 +17,7 @@ import ( | |||
"github.com/gogits/gogs/modules/setting" | |||
) | |||
const APP_VER = "0.9.5.0311" | |||
const APP_VER = "0.9.6.0311" | |||
func init() { | |||
runtime.GOMAXPROCS(runtime.NumCPU()) |
@@ -169,7 +169,7 @@ func GetOrgByName(name string) (*User, error) { | |||
} | |||
u := &User{ | |||
LowerName: strings.ToLower(name), | |||
Type: ORGANIZATION, | |||
Type: USER_TYPE_ORGANIZATION, | |||
} | |||
has, err := x.Get(u) | |||
if err != nil { |
@@ -1049,11 +1049,16 @@ func CountPublicRepositories() int64 { | |||
return countRepositories(false) | |||
} | |||
func Repositories(page, pageSize int) (_ []*Repository, err error) { | |||
repos := make([]*Repository, 0, pageSize) | |||
return repos, x.Limit(pageSize, (page-1)*pageSize).Asc("id").Find(&repos) | |||
} | |||
// RepositoriesWithUsers returns number of repos in given page. | |||
func RepositoriesWithUsers(page, pageSize int) (_ []*Repository, err error) { | |||
repos := make([]*Repository, 0, pageSize) | |||
if err = x.Limit(pageSize, (page-1)*pageSize).Asc("id").Find(&repos); err != nil { | |||
return nil, err | |||
repos, err := Repositories(page, pageSize) | |||
if err != nil { | |||
return nil, fmt.Errorf("Repositories: %v", err) | |||
} | |||
for i := range repos { | |||
@@ -1474,9 +1479,9 @@ func GetRepositories(uid int64, private bool) ([]*Repository, error) { | |||
} | |||
// GetRecentUpdatedRepositories returns the list of repositories that are recently updated. | |||
func GetRecentUpdatedRepositories(page int) (repos []*Repository, err error) { | |||
return repos, x.Limit(setting.ExplorePagingNum, (page-1)*setting.ExplorePagingNum). | |||
Where("is_private=?", false).Limit(setting.ExplorePagingNum).Desc("updated_unix").Find(&repos) | |||
func GetRecentUpdatedRepositories(page, pageSize int) (repos []*Repository, err error) { | |||
return repos, x.Limit(pageSize, (page-1)*pageSize). | |||
Where("is_private=?", false).Limit(pageSize).Desc("updated_unix").Find(&repos) | |||
} | |||
func getRepositoryCount(e Engine, u *User) (int64, error) { | |||
@@ -1488,32 +1493,52 @@ func GetRepositoryCount(u *User) (int64, error) { | |||
return getRepositoryCount(x, u) | |||
} | |||
type SearchOption struct { | |||
Keyword string | |||
Uid int64 | |||
Limit int | |||
Private bool | |||
type SearchRepoOptions struct { | |||
Keyword string | |||
OwnerID int64 | |||
OrderBy string | |||
Private bool // Include private repositories in results | |||
Page int | |||
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum | |||
} | |||
// SearchRepositoryByName returns given number of repositories whose name contains keyword. | |||
func SearchRepositoryByName(opt SearchOption) (repos []*Repository, err error) { | |||
if len(opt.Keyword) == 0 { | |||
return repos, nil | |||
// SearchRepositoryByName takes keyword and part of repository name to search, | |||
// it returns results in given range and number of total results. | |||
func SearchRepositoryByName(opts *SearchRepoOptions) (repos []*Repository, _ int64, _ error) { | |||
if len(opts.Keyword) == 0 { | |||
return repos, 0, nil | |||
} | |||
opts.Keyword = strings.ToLower(opts.Keyword) | |||
if opts.PageSize <= 0 || opts.PageSize > setting.ExplorePagingNum { | |||
opts.PageSize = setting.ExplorePagingNum | |||
} | |||
if opts.Page <= 0 { | |||
opts.Page = 1 | |||
} | |||
opt.Keyword = strings.ToLower(opt.Keyword) | |||
repos = make([]*Repository, 0, opt.Limit) | |||
repos = make([]*Repository, 0, opts.PageSize) | |||
// Append conditions. | |||
sess := x.Limit(opt.Limit) | |||
if opt.Uid > 0 { | |||
sess.Where("owner_id=?", opt.Uid) | |||
// Append conditions | |||
sess := x.Where("lower_name like ?", "%"+opts.Keyword+"%") | |||
if opts.OwnerID > 0 { | |||
sess.And("owner_id = ?", opts.OwnerID) | |||
} | |||
if !opt.Private { | |||
if !opts.Private { | |||
sess.And("is_private=?", false) | |||
} | |||
sess.And("lower_name like ?", "%"+opt.Keyword+"%").Find(&repos) | |||
return repos, err | |||
if len(opts.OrderBy) > 0 { | |||
sess.OrderBy(opts.OrderBy) | |||
} | |||
var countSess xorm.Session | |||
countSess = *sess | |||
count, err := countSess.Count(new(Repository)) | |||
if err != nil { | |||
return nil, 0, fmt.Errorf("Count: %v", err) | |||
} | |||
return repos, count, sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&repos) | |||
} | |||
// DeleteRepositoryArchives deletes all repositories' archives. |
@@ -36,8 +36,8 @@ import ( | |||
type UserType int | |||
const ( | |||
INDIVIDUAL UserType = iota // Historic reason to make it starts at 0. | |||
ORGANIZATION | |||
USER_TYPE_INDIVIDUAL UserType = iota // Historic reason to make it starts at 0. | |||
USER_TYPE_ORGANIZATION | |||
) | |||
var ( | |||
@@ -389,7 +389,7 @@ func (u *User) IsWriterOfRepo(repo *Repository) bool { | |||
// IsOrganization returns true if user is actually a organization. | |||
func (u *User) IsOrganization() bool { | |||
return u.Type == ORGANIZATION | |||
return u.Type == USER_TYPE_ORGANIZATION | |||
} | |||
// IsUserOrgOwner returns true if user is in the owner team of given organization. | |||
@@ -1114,16 +1114,45 @@ func GetUserByEmail(email string) (*User, error) { | |||
return nil, ErrUserNotExist{0, email} | |||
} | |||
// SearchUserByName returns given number of users whose name contains keyword. | |||
func SearchUserByName(opt SearchOption) (us []*User, err error) { | |||
if len(opt.Keyword) == 0 { | |||
return us, nil | |||
type SearchUserOptions struct { | |||
Keyword string | |||
Type UserType | |||
OrderBy string | |||
Page int | |||
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum | |||
} | |||
// SearchUserByName takes keyword and part of user name to search, | |||
// it returns results in given range and number of total results. | |||
func SearchUserByName(opts *SearchUserOptions) (users []*User, _ int64, _ error) { | |||
if len(opts.Keyword) == 0 { | |||
return users, 0, nil | |||
} | |||
opts.Keyword = strings.ToLower(opts.Keyword) | |||
if opts.PageSize <= 0 || opts.PageSize > setting.ExplorePagingNum { | |||
opts.PageSize = setting.ExplorePagingNum | |||
} | |||
if opts.Page <= 0 { | |||
opts.Page = 1 | |||
} | |||
users = make([]*User, 0, opts.PageSize) | |||
// Append conditions | |||
fmt.Println(opts.Type) | |||
sess := x.Where("lower_name like ?", "%"+opts.Keyword+"%").And("type = ?", opts.Type) | |||
if len(opts.OrderBy) > 0 { | |||
sess.OrderBy(opts.OrderBy) | |||
} | |||
var countSess xorm.Session | |||
countSess = *sess | |||
count, err := countSess.Count(new(User)) | |||
if err != nil { | |||
return nil, 0, fmt.Errorf("Count: %v", err) | |||
} | |||
opt.Keyword = strings.ToLower(opt.Keyword) | |||
us = make([]*User, 0, opt.Limit) | |||
err = x.Limit(opt.Limit).Where("type=0").And("lower_name like ?", "%"+opt.Keyword+"%").Find(&us) | |||
return us, err | |||
return users, count, sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&users) | |||
} | |||
// ___________ .__ .__ |
@@ -441,30 +441,30 @@ | |||
"outputStyle": 1, | |||
"syntaxCheckerStyle": 1 | |||
}, | |||
"\/plugins\/highlight-9.1.0\/default.css": { | |||
"\/plugins\/highlight-9.2.0\/default.css": { | |||
"fileType": 16, | |||
"ignore": 0, | |||
"ignoreWasSetByUser": 0, | |||
"inputAbbreviatedPath": "\/plugins\/highlight-9.1.0\/default.css", | |||
"inputAbbreviatedPath": "\/plugins\/highlight-9.2.0\/default.css", | |||
"outputAbbreviatedPath": "No Output Path", | |||
"outputPathIsOutsideProject": 0, | |||
"outputPathIsSetByUser": 0 | |||
}, | |||
"\/plugins\/highlight-9.1.0\/github.css": { | |||
"\/plugins\/highlight-9.2.0\/github.css": { | |||
"fileType": 16, | |||
"ignore": 0, | |||
"ignoreWasSetByUser": 0, | |||
"inputAbbreviatedPath": "\/plugins\/highlight-9.1.0\/github.css", | |||
"inputAbbreviatedPath": "\/plugins\/highlight-9.2.0\/github.css", | |||
"outputAbbreviatedPath": "No Output Path", | |||
"outputPathIsOutsideProject": 0, | |||
"outputPathIsSetByUser": 0 | |||
}, | |||
"\/plugins\/highlight-9.1.0\/highlight.pack.js": { | |||
"\/plugins\/highlight-9.2.0\/highlight.pack.js": { | |||
"fileType": 64, | |||
"ignore": 0, | |||
"ignoreWasSetByUser": 0, | |||
"inputAbbreviatedPath": "\/plugins\/highlight-9.1.0\/highlight.pack.js", | |||
"outputAbbreviatedPath": "\/plugins\/highlight-9.1.0\/min\/highlight.pack-min.js", | |||
"inputAbbreviatedPath": "\/plugins\/highlight-9.2.0\/highlight.pack.js", | |||
"outputAbbreviatedPath": "\/plugins\/highlight-9.2.0\/min\/highlight.pack-min.js", | |||
"outputPathIsOutsideProject": 0, | |||
"outputPathIsSetByUser": 0, | |||
"outputStyle": 1, |
@@ -2594,6 +2594,10 @@ footer .container .links > *:first-child { | |||
padding-top: 15px; | |||
padding-bottom: 80px; | |||
} | |||
.explore .navbar .octicon { | |||
width: 16px; | |||
text-align: center; | |||
} | |||
.ui.repository.list .item { | |||
padding-bottom: 25px; | |||
} | |||
@@ -2620,3 +2624,26 @@ footer .container .links > *:first-child { | |||
font-size: 12px; | |||
color: #808080; | |||
} | |||
.ui.user.list .item { | |||
padding-bottom: 25px; | |||
} | |||
.ui.user.list .item:not(:first-child) { | |||
border-top: 1px solid #eee; | |||
padding-top: 25px; | |||
} | |||
.ui.user.list .item .ui.avatar.image { | |||
width: 40px; | |||
height: 40px; | |||
} | |||
.ui.user.list .item .description { | |||
margin-top: 5px; | |||
} | |||
.ui.user.list .item .description .octicon:not(:first-child) { | |||
margin-left: 5px; | |||
} | |||
.ui.user.list .item .description a { | |||
color: #333; | |||
} | |||
.ui.user.list .item .description a:hover { | |||
text-decoration: underline; | |||
} |
@@ -1,6 +1,13 @@ | |||
.explore { | |||
padding-top: 15px; | |||
padding-bottom: @footer-margin * 2; | |||
.navbar { | |||
.octicon { | |||
width: 16px; | |||
text-align: center; | |||
} | |||
} | |||
} | |||
.ui.repository.list { | |||
@@ -35,3 +42,34 @@ | |||
} | |||
} | |||
} | |||
.ui.user.list { | |||
.item { | |||
padding-bottom: 25px; | |||
&:not(:first-child) { | |||
border-top: 1px solid #eee; | |||
padding-top: 25px; | |||
} | |||
.ui.avatar.image { | |||
width: 40px; | |||
height: 40px; | |||
} | |||
.description { | |||
margin-top: 5px; | |||
.octicon:not(:first-child) { | |||
margin-left: 5px; | |||
} | |||
a { | |||
color: #333; | |||
&:hover { | |||
text-decoration: underline; | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -5,12 +5,11 @@ | |||
package admin | |||
import ( | |||
"github.com/Unknwon/paginater" | |||
"github.com/gogits/gogs/models" | |||
"github.com/gogits/gogs/modules/base" | |||
"github.com/gogits/gogs/modules/context" | |||
"github.com/gogits/gogs/modules/setting" | |||
"github.com/gogits/gogs/routers" | |||
) | |||
const ( | |||
@@ -22,22 +21,6 @@ func Organizations(ctx *context.Context) { | |||
ctx.Data["PageIsAdmin"] = true | |||
ctx.Data["PageIsAdminOrganizations"] = true | |||
total := models.CountOrganizations() | |||
page := ctx.QueryInt("page") | |||
if page <= 1 { | |||
page = 1 | |||
} | |||
ctx.Data["Page"] = paginater.New(int(total), setting.AdminOrgPagingNum, page, 5) | |||
orgs, err := models.Organizations(page, setting.AdminOrgPagingNum) | |||
if err != nil { | |||
ctx.Handle(500, "Organizations", err) | |||
return | |||
} | |||
ctx.Data["Orgs"] = orgs | |||
ctx.Data["Total"] = total | |||
ctx.HTML(200, ORGS) | |||
routers.RenderUserSearch(ctx, models.USER_TYPE_ORGANIZATION, models.CountOrganizations, models.Organizations, | |||
setting.AdminOrgPagingNum, "id ASC", ORGS) | |||
} |
@@ -5,13 +5,12 @@ | |||
package admin | |||
import ( | |||
"github.com/Unknwon/paginater" | |||
"github.com/gogits/gogs/models" | |||
"github.com/gogits/gogs/modules/base" | |||
"github.com/gogits/gogs/modules/context" | |||
"github.com/gogits/gogs/modules/log" | |||
"github.com/gogits/gogs/modules/setting" | |||
"github.com/gogits/gogs/routers" | |||
) | |||
const ( | |||
@@ -23,22 +22,8 @@ func Repos(ctx *context.Context) { | |||
ctx.Data["PageIsAdmin"] = true | |||
ctx.Data["PageIsAdminRepositories"] = true | |||
total := models.CountRepositories() | |||
page := ctx.QueryInt("page") | |||
if page <= 1 { | |||
page = 1 | |||
} | |||
ctx.Data["Page"] = paginater.New(int(total), setting.AdminRepoPagingNum, page, 5) | |||
repos, err := models.RepositoriesWithUsers(page, setting.AdminRepoPagingNum) | |||
if err != nil { | |||
ctx.Handle(500, "RepositoriesWithUsers", err) | |||
return | |||
} | |||
ctx.Data["Repos"] = repos | |||
ctx.Data["Total"] = total | |||
ctx.HTML(200, REPOS) | |||
routers.RenderRepoSearch(ctx, models.CountRepositories, models.Repositories, | |||
setting.AdminRepoPagingNum, "id ASC", REPOS) | |||
} | |||
func DeleteRepo(ctx *context.Context) { |
@@ -8,7 +8,6 @@ import ( | |||
"strings" | |||
"github.com/Unknwon/com" | |||
"github.com/Unknwon/paginater" | |||
"github.com/gogits/gogs/models" | |||
"github.com/gogits/gogs/modules/auth" | |||
@@ -17,6 +16,7 @@ import ( | |||
"github.com/gogits/gogs/modules/log" | |||
"github.com/gogits/gogs/modules/mailer" | |||
"github.com/gogits/gogs/modules/setting" | |||
"github.com/gogits/gogs/routers" | |||
) | |||
const ( | |||
@@ -30,22 +30,8 @@ func Users(ctx *context.Context) { | |||
ctx.Data["PageIsAdmin"] = true | |||
ctx.Data["PageIsAdminUsers"] = true | |||
total := models.CountUsers() | |||
page := ctx.QueryInt("page") | |||
if page <= 1 { | |||
page = 1 | |||
} | |||
ctx.Data["Page"] = paginater.New(int(total), setting.AdminUserPagingNum, page, 5) | |||
users, err := models.Users(page, setting.AdminUserPagingNum) | |||
if err != nil { | |||
ctx.Handle(500, "Users", err) | |||
return | |||
} | |||
ctx.Data["Users"] = users | |||
ctx.Data["Total"] = total | |||
ctx.HTML(200, USERS) | |||
routers.RenderUserSearch(ctx, models.USER_TYPE_INDIVIDUAL, models.CountUsers, models.Users, | |||
setting.AdminUserPagingNum, "id ASC", USERS) | |||
} | |||
func NewUser(ctx *context.Context) { |
@@ -27,7 +27,7 @@ func CreateOrg(ctx *context.Context, form api.CreateOrgOption) { | |||
Website: form.Website, | |||
Location: form.Location, | |||
IsActive: true, | |||
Type: models.ORGANIZATION, | |||
Type: models.USER_TYPE_ORGANIZATION, | |||
} | |||
if err := models.CreateOrganization(org, u); err != nil { | |||
if models.IsErrUserAlreadyExist(err) || |
@@ -21,21 +21,21 @@ import ( | |||
// https://github.com/gogits/go-gogs-client/wiki/Repositories#search-repositories | |||
func Search(ctx *context.Context) { | |||
opt := models.SearchOption{ | |||
Keyword: path.Base(ctx.Query("q")), | |||
Uid: com.StrTo(ctx.Query("uid")).MustInt64(), | |||
Limit: com.StrTo(ctx.Query("limit")).MustInt(), | |||
opts := &models.SearchRepoOptions{ | |||
Keyword: path.Base(ctx.Query("q")), | |||
OwnerID: com.StrTo(ctx.Query("uid")).MustInt64(), | |||
PageSize: com.StrTo(ctx.Query("limit")).MustInt(), | |||
} | |||
if opt.Limit == 0 { | |||
opt.Limit = 10 | |||
if opts.PageSize == 0 { | |||
opts.PageSize = 10 | |||
} | |||
// Check visibility. | |||
if ctx.IsSigned && opt.Uid > 0 { | |||
if ctx.User.Id == opt.Uid { | |||
opt.Private = true | |||
if ctx.IsSigned && opts.OwnerID > 0 { | |||
if ctx.User.Id == opts.OwnerID { | |||
opts.Private = true | |||
} else { | |||
u, err := models.GetUserByID(opt.Uid) | |||
u, err := models.GetUserByID(opts.OwnerID) | |||
if err != nil { | |||
ctx.JSON(500, map[string]interface{}{ | |||
"ok": false, | |||
@@ -44,13 +44,13 @@ func Search(ctx *context.Context) { | |||
return | |||
} | |||
if u.IsOrganization() && u.IsOwnedBy(ctx.User.Id) { | |||
opt.Private = true | |||
opts.Private = true | |||
} | |||
// FIXME: how about collaborators? | |||
} | |||
} | |||
repos, err := models.SearchRepositoryByName(opt) | |||
repos, _, err := models.SearchRepositoryByName(opts) | |||
if err != nil { | |||
ctx.JSON(500, map[string]interface{}{ | |||
"ok": false, |
@@ -15,15 +15,16 @@ import ( | |||
// https://github.com/gogits/go-gogs-client/wiki/Users#search-users | |||
func Search(ctx *context.Context) { | |||
opt := models.SearchOption{ | |||
Keyword: ctx.Query("q"), | |||
Limit: com.StrTo(ctx.Query("limit")).MustInt(), | |||
opts := &models.SearchUserOptions{ | |||
Keyword: ctx.Query("q"), | |||
Type: models.USER_TYPE_INDIVIDUAL, | |||
PageSize: com.StrTo(ctx.Query("limit")).MustInt(), | |||
} | |||
if opt.Limit == 0 { | |||
opt.Limit = 10 | |||
if opts.PageSize == 0 { | |||
opts.PageSize = 10 | |||
} | |||
us, err := models.SearchUserByName(opt) | |||
users, _, err := models.SearchUserByName(opts) | |||
if err != nil { | |||
ctx.JSON(500, map[string]interface{}{ | |||
"ok": false, | |||
@@ -32,16 +33,16 @@ func Search(ctx *context.Context) { | |||
return | |||
} | |||
results := make([]*api.User, len(us)) | |||
for i := range us { | |||
results := make([]*api.User, len(users)) | |||
for i := range users { | |||
results[i] = &api.User{ | |||
ID: us[i].Id, | |||
UserName: us[i].Name, | |||
AvatarUrl: us[i].AvatarLink(), | |||
FullName: us[i].FullName, | |||
ID: users[i].Id, | |||
UserName: users[i].Name, | |||
AvatarUrl: users[i].AvatarLink(), | |||
FullName: users[i].FullName, | |||
} | |||
if ctx.IsSigned { | |||
results[i].Email = us[i].Email | |||
results[i].Email = users[i].Email | |||
} | |||
} | |||
@@ -19,6 +19,7 @@ import ( | |||
const ( | |||
HOME base.TplName = "home" | |||
EXPLORE_REPOS base.TplName = "explore/repos" | |||
EXPLORE_USERS base.TplName = "explore/users" | |||
) | |||
func Home(ctx *context.Context) { | |||
@@ -43,23 +44,44 @@ func Home(ctx *context.Context) { | |||
ctx.HTML(200, HOME) | |||
} | |||
func Explore(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("explore") | |||
ctx.Data["PageIsExplore"] = true | |||
ctx.Data["PageIsExploreRepositories"] = true | |||
func RenderRepoSearch(ctx *context.Context, | |||
counter func() int64, ranger func(int, int) ([]*models.Repository, error), | |||
pagingNum int, orderBy string, tplName base.TplName) { | |||
page := ctx.QueryInt("page") | |||
if page <= 1 { | |||
page = 1 | |||
} | |||
ctx.Data["Page"] = paginater.New(int(models.CountPublicRepositories()), setting.ExplorePagingNum, page, 5) | |||
var ( | |||
repos []*models.Repository | |||
count int64 | |||
err error | |||
) | |||
repos, err := models.GetRecentUpdatedRepositories(page) | |||
if err != nil { | |||
ctx.Handle(500, "GetRecentUpdatedRepositories", err) | |||
return | |||
keyword := ctx.Query("q") | |||
if len(keyword) == 0 { | |||
repos, err = ranger(page, pagingNum) | |||
if err != nil { | |||
ctx.Handle(500, "ranger", err) | |||
return | |||
} | |||
count = counter() | |||
} else { | |||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{ | |||
Keyword: keyword, | |||
OrderBy: orderBy, | |||
Page: page, | |||
PageSize: pagingNum, | |||
}) | |||
if err != nil { | |||
ctx.Handle(500, "SearchRepositoryByName", err) | |||
return | |||
} | |||
} | |||
ctx.Data["Keyword"] = keyword | |||
ctx.Data["Total"] = count | |||
ctx.Data["Page"] = paginater.New(int(count), pagingNum, page, 5) | |||
for _, repo := range repos { | |||
if err = repo.GetOwner(); err != nil { | |||
ctx.Handle(500, "GetOwner", fmt.Errorf("%d: %v", repo.ID, err)) | |||
@@ -68,7 +90,68 @@ func Explore(ctx *context.Context) { | |||
} | |||
ctx.Data["Repos"] = repos | |||
ctx.HTML(200, EXPLORE_REPOS) | |||
ctx.HTML(200, tplName) | |||
} | |||
func ExploreRepos(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("explore") | |||
ctx.Data["PageIsExplore"] = true | |||
ctx.Data["PageIsExploreRepositories"] = true | |||
RenderRepoSearch(ctx, models.CountPublicRepositories, models.GetRecentUpdatedRepositories, | |||
setting.ExplorePagingNum, "updated_unix DESC", EXPLORE_REPOS) | |||
} | |||
func RenderUserSearch(ctx *context.Context, userType models.UserType, | |||
counter func() int64, ranger func(int, int) ([]*models.User, error), | |||
pagingNum int, orderBy string, tplName base.TplName) { | |||
page := ctx.QueryInt("page") | |||
if page <= 1 { | |||
page = 1 | |||
} | |||
var ( | |||
users []*models.User | |||
count int64 | |||
err error | |||
) | |||
keyword := ctx.Query("q") | |||
if len(keyword) == 0 { | |||
users, err = ranger(page, pagingNum) | |||
if err != nil { | |||
ctx.Handle(500, "ranger", err) | |||
return | |||
} | |||
count = counter() | |||
} else { | |||
users, count, err = models.SearchUserByName(&models.SearchUserOptions{ | |||
Keyword: keyword, | |||
Type: userType, | |||
OrderBy: orderBy, | |||
Page: page, | |||
PageSize: pagingNum, | |||
}) | |||
if err != nil { | |||
ctx.Handle(500, "SearchUserByName", err) | |||
return | |||
} | |||
} | |||
ctx.Data["Keyword"] = keyword | |||
ctx.Data["Total"] = count | |||
ctx.Data["Page"] = paginater.New(int(count), pagingNum, page, 5) | |||
ctx.Data["Users"] = users | |||
ctx.HTML(200, tplName) | |||
} | |||
func ExploreUsers(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("explore") | |||
ctx.Data["PageIsExplore"] = true | |||
ctx.Data["PageIsExploreUsers"] = true | |||
RenderUserSearch(ctx, models.USER_TYPE_INDIVIDUAL, models.CountUsers, models.Users, | |||
setting.ExplorePagingNum, "updated_unix DESC", EXPLORE_USERS) | |||
} | |||
func NotFound(ctx *context.Context) { |
@@ -33,7 +33,7 @@ func CreatePost(ctx *context.Context, form auth.CreateOrgForm) { | |||
org := &models.User{ | |||
Name: form.OrgName, | |||
IsActive: true, | |||
Type: models.ORGANIZATION, | |||
Type: models.USER_TYPE_ORGANIZATION, | |||
} | |||
if err := models.CreateOrganization(org, ctx.User); err != nil { |
@@ -1 +1 @@ | |||
0.9.5.0311 | |||
0.9.6.0311 |
@@ -0,0 +1,23 @@ | |||
{{with .Page}} | |||
{{if gt .TotalPages 1}} | |||
<div class="center page buttons"> | |||
<div class="ui borderless pagination menu"> | |||
<a class="{{if .IsFirst}}disabled{{end}} item" href="{{$.Link}}?q={{$.Keyword}}"><i class="angle double left icon"></i> {{$.i18n.Tr "admin.first_page"}}</a> | |||
<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}&q={{$.Keyword}}"{{end}}> | |||
<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}} | |||
</a> | |||
{{range .Pages}} | |||
{{if eq .Num -1}} | |||
<a class="disabled item">...</a> | |||
{{else}} | |||
<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}&q={{$.Keyword}}"{{end}}>{{.Num}}</a> | |||
{{end}} | |||
{{end}} | |||
<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}&q={{$.Keyword}}"{{end}}> | |||
{{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i> | |||
</a> | |||
<a class="{{if .IsLast}}disabled{{end}} item" href="{{$.Link}}?page={{.TotalPages}}&q={{$.Keyword}}">{{$.i18n.Tr "admin.last_page"}} <i class="angle double right icon"></i></a> | |||
</div> | |||
</div> | |||
{{end}} | |||
{{end}} |
@@ -0,0 +1,6 @@ | |||
<form class="ui form"> | |||
<div class="ui fluid action input"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus> | |||
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button> | |||
</div> | |||
</form> |
@@ -8,6 +8,9 @@ | |||
<h4 class="ui top attached header"> | |||
{{.i18n.Tr "admin.orgs.org_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}}) | |||
</h4> | |||
<div class="ui attached segment"> | |||
{{template "admin/base/search" .}} | |||
</div> | |||
<div class="ui attached table segment"> | |||
<table class="ui very basic striped table"> | |||
<thead> | |||
@@ -22,7 +25,7 @@ | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{{range .Orgs}} | |||
{{range .Users}} | |||
<tr> | |||
<td>{{.Id}}</td> | |||
<td><a href="{{.HomeLink}}">{{.Name}}</a></td> | |||
@@ -37,29 +40,7 @@ | |||
</table> | |||
</div> | |||
{{with .Page}} | |||
{{if gt .TotalPages 1}} | |||
<div class="center page buttons"> | |||
<div class="ui borderless pagination menu"> | |||
<a class="{{if .IsFirst}}disabled{{end}} item" href="{{$.Link}}"><i class="angle double left icon"></i> {{$.i18n.Tr "admin.first_page"}}</a> | |||
<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}"{{end}}> | |||
<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}} | |||
</a> | |||
{{range .Pages}} | |||
{{if eq .Num -1}} | |||
<a class="disabled item">...</a> | |||
{{else}} | |||
<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}"{{end}}>{{.Num}}</a> | |||
{{end}} | |||
{{end}} | |||
<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}"{{end}}> | |||
{{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i> | |||
</a> | |||
<a class="{{if .IsLast}}disabled{{end}} item" href="{{$.Link}}?page={{.TotalPages}}">{{$.i18n.Tr "admin.last_page"}} <i class="angle double right icon"></i></a> | |||
</div> | |||
</div> | |||
{{end}} | |||
{{end}} | |||
{{template "admin/base/page" .}} | |||
</div> | |||
</div> | |||
</div> |
@@ -8,6 +8,9 @@ | |||
<h4 class="ui top attached header"> | |||
{{.i18n.Tr "admin.repos.repo_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}}) | |||
</h4> | |||
<div class="ui attached segment"> | |||
{{template "admin/base/search" .}} | |||
</div> | |||
<div class="ui attached table segment"> | |||
<table class="ui very basic striped table"> | |||
<thead> | |||
@@ -41,29 +44,7 @@ | |||
</table> | |||
</div> | |||
{{with .Page}} | |||
{{if gt .TotalPages 1}} | |||
<div class="center page buttons"> | |||
<div class="ui borderless pagination menu"> | |||
<a class="{{if .IsFirst}}disabled{{end}} item" href="{{$.Link}}"><i class="angle double left icon"></i> {{$.i18n.Tr "admin.first_page"}}</a> | |||
<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}"{{end}}> | |||
<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}} | |||
</a> | |||
{{range .Pages}} | |||
{{if eq .Num -1}} | |||
<a class="disabled item">...</a> | |||
{{else}} | |||
<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}"{{end}}>{{.Num}}</a> | |||
{{end}} | |||
{{end}} | |||
<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}"{{end}}> | |||
{{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i> | |||
</a> | |||
<a class="{{if .IsLast}}disabled{{end}} item" href="{{$.Link}}?page={{.TotalPages}}">{{$.i18n.Tr "admin.last_page"}} <i class="angle double right icon"></i></a> | |||
</div> | |||
</div> | |||
{{end}} | |||
{{end}} | |||
{{template "admin/base/page" .}} | |||
</div> | |||
</div> | |||
</div> |
@@ -8,9 +8,12 @@ | |||
<h4 class="ui top attached header"> | |||
{{.i18n.Tr "admin.users.user_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}}) | |||
<div class="ui right"> | |||
<a class="ui blue tiny button" href="{{AppSubUrl}}/admin/users/new">{{.i18n.Tr "admin.users.new_account"}}</a> | |||
<a class="ui black tiny button" href="{{AppSubUrl}}/admin/users/new">{{.i18n.Tr "admin.users.new_account"}}</a> | |||
</div> | |||
</h4> | |||
<div class="ui attached segment"> | |||
{{template "admin/base/search" .}} | |||
</div> | |||
<div class="ui attached table segment"> | |||
<table class="ui very basic striped table"> | |||
<thead> | |||
@@ -42,29 +45,7 @@ | |||
</table> | |||
</div> | |||
{{with .Page}} | |||
{{if gt .TotalPages 1}} | |||
<div class="center page buttons"> | |||
<div class="ui borderless pagination menu"> | |||
<a class="{{if .IsFirst}}disabled{{end}} item" href="{{$.Link}}"><i class="angle double left icon"></i> {{$.i18n.Tr "admin.first_page"}}</a> | |||
<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}"{{end}}> | |||
<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}} | |||
</a> | |||
{{range .Pages}} | |||
{{if eq .Num -1}} | |||
<a class="disabled item">...</a> | |||
{{else}} | |||
<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}"{{end}}>{{.Num}}</a> | |||
{{end}} | |||
{{end}} | |||
<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}"{{end}}> | |||
{{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i> | |||
</a> | |||
<a class="{{if .IsLast}}disabled{{end}} item" href="{{$.Link}}?page={{.TotalPages}}">{{$.i18n.Tr "admin.last_page"}} <i class="angle double right icon"></i></a> | |||
</div> | |||
</div> | |||
{{end}} | |||
{{end}} | |||
{{template "admin/base/page" .}} | |||
</div> | |||
</div> | |||
</div> |
@@ -59,7 +59,7 @@ | |||
<a class="item{{if .PageIsHome}} active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "home"}}</a> | |||
{{end}} | |||
<a class="item{{if .PageIsExplore}} active{{end}}" href="{{AppSubUrl}}/explore">{{.i18n.Tr "explore"}}</a> | |||
<a class="item{{if .PageIsExplore}} active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "explore"}}</a> | |||
{{/*<div class="item"> | |||
<div class="ui icon input"> | |||
<input class="searchbox" type="text" placeholder="{{.i18n.Tr "search_project"}}"> |
@@ -1,8 +1,11 @@ | |||
<div class="four wide column"> | |||
<div class="ui vertical menu"> | |||
<div class="ui vertical menu navbar"> | |||
<div class="header item">{{.i18n.Tr "explore"}}</div> | |||
<a class="{{if .PageIsExploreRepositories}}active{{end}} item" href="{{AppSubUrl}}/explore"> | |||
{{.i18n.Tr "explore.repos"}} | |||
<a class="{{if .PageIsExploreRepositories}}active{{end}} item" href="{{AppSubUrl}}/explore/repos"> | |||
<span class="octicon octicon-repo"></span> {{.i18n.Tr "explore.repos"}} | |||
</a> | |||
<a class="{{if .PageIsExploreUsers}}active{{end}} item" href="{{AppSubUrl}}/explore/users"> | |||
<span class="octicon octicon-person"></span> {{.i18n.Tr "explore.users"}} | |||
</a> | |||
</div> | |||
</div> |
@@ -0,0 +1,21 @@ | |||
{{with .Page}} | |||
{{if gt .TotalPages 1}} | |||
<div class="center page buttons"> | |||
<div class="ui borderless pagination menu"> | |||
<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}&q={{$.Keyword}}"{{end}}> | |||
<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}} | |||
</a> | |||
{{range .Pages}} | |||
{{if eq .Num -1}} | |||
<a class="disabled item">...</a> | |||
{{else}} | |||
<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}&q={{$.Keyword}}"{{end}}>{{.Num}}</a> | |||
{{end}} | |||
{{end}} | |||
<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}&q={{$.Keyword}}"{{end}}> | |||
{{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i> | |||
</a> | |||
</div> | |||
</div> | |||
{{end}} | |||
{{end}} |
@@ -4,29 +4,9 @@ | |||
<div class="ui grid"> | |||
{{template "explore/navbar" .}} | |||
<div class="twelve wide column content"> | |||
{{template "explore/search" .}} | |||
{{template "explore/repo_list" .}} | |||
{{with .Page}} | |||
{{if gt .TotalPages 1}} | |||
<div class="center page buttons"> | |||
<div class="ui borderless pagination menu"> | |||
<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}"{{end}}> | |||
<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}} | |||
</a> | |||
{{range .Pages}} | |||
{{if eq .Num -1}} | |||
<a class="disabled item">...</a> | |||
{{else}} | |||
<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}"{{end}}>{{.Num}}</a> | |||
{{end}} | |||
{{end}} | |||
<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}"{{end}}> | |||
{{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i> | |||
</a> | |||
</div> | |||
</div> | |||
{{end}} | |||
{{end}} | |||
{{template "explore/page" .}} | |||
</div> | |||
</div> | |||
</div> |
@@ -0,0 +1,7 @@ | |||
<form class="ui form"> | |||
<div class="ui fluid action input"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus> | |||
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button> | |||
</div> | |||
</form> | |||
<div class="ui divider"></div> |
@@ -0,0 +1,35 @@ | |||
{{template "base/head" .}} | |||
<div class="explore users"> | |||
<div class="ui container"> | |||
<div class="ui grid"> | |||
{{template "explore/navbar" .}} | |||
<div class="twelve wide column content"> | |||
{{template "explore/search" .}} | |||
<div class="ui user list"> | |||
{{range .Users}} | |||
<div class="item"> | |||
<img class="ui avatar image" src="{{.AvatarLink}}"> | |||
<div class="content"> | |||
<span class="header"><a href="{{.HomeLink}}">{{.Name}}</a> {{.FullName}}</span> | |||
<div class="description"> | |||
{{if .Location}} | |||
<i class="octicon octicon-location"></i> {{.Location}} | |||
{{end}} | |||
{{if and .Email $.IsSigned}} | |||
<i class="octicon octicon-mail"></i> | |||
<a href="mailto:{{.Email}}" rel="nofollow">{{.Email}}</a> | |||
{{end}} | |||
<i class="octicon octicon-clock"></i> {{$.i18n.Tr "user.join_on"}} {{DateFmtShort .Created}} | |||
</div> | |||
</div> | |||
</div> | |||
{{end}} | |||
</div> | |||
{{template "explore/page" .}} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |