templates: make state changing routes to POST method (#5541)

- pkg/context: add ParamsUser to unify the injection process
pull/5340/head^2
Unknwon 2018-12-06 22:58:02 -05:00
parent 458aadbb10
commit f545faa06d
No known key found for this signature in database
GPG Key ID: 25B575AE3213B2B3
12 changed files with 190 additions and 166 deletions

View File

@ -257,7 +257,7 @@ func runWeb(c *cli.Context) error {
m.Get("/email2user", user.Email2User) m.Get("/email2user", user.Email2User)
m.Get("/forget_password", user.ForgotPasswd) m.Get("/forget_password", user.ForgotPasswd)
m.Post("/forget_password", user.ForgotPasswdPost) m.Post("/forget_password", user.ForgotPasswdPost)
m.Get("/logout", user.SignOut) m.Post("/logout", user.SignOut)
}) })
// ***** END: User ***** // ***** END: User *****
@ -308,7 +308,7 @@ func runWeb(c *cli.Context) error {
m.Get("/followers", user.Followers) m.Get("/followers", user.Followers)
m.Get("/following", user.Following) m.Get("/following", user.Following)
m.Get("/stars", user.Stars) m.Get("/stars", user.Stars)
}) }, context.InjectParamsUser())
m.Get("/attachments/:uuid", func(c *context.Context) { m.Get("/attachments/:uuid", func(c *context.Context) {
attach, err := models.GetAttachmentByUUID(c.Params(":uuid")) attach, err := models.GetAttachmentByUUID(c.Params(":uuid"))
@ -340,8 +340,8 @@ func runWeb(c *cli.Context) error {
}, ignSignIn) }, ignSignIn)
m.Group("/:username", func() { m.Group("/:username", func() {
m.Get("/action/:action", user.Action) m.Post("/action/:action", user.Action)
}, reqSignIn) }, reqSignIn, context.InjectParamsUser())
if macaron.Env == macaron.DEV { if macaron.Env == macaron.DEV {
m.Get("/template/*", dev.TemplatePreview) m.Get("/template/*", dev.TemplatePreview)
@ -484,7 +484,7 @@ func runWeb(c *cli.Context) error {
}) })
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef()) }, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action) m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
m.Group("/:username/:reponame", func() { m.Group("/:username/:reponame", func() {
m.Get("/issues", repo.RetrieveLabels, repo.Issues) m.Get("/issues", repo.RetrieveLabels, repo.Issues)
m.Get("/issues/:index", repo.ViewIssue) m.Get("/issues/:index", repo.ViewIssue)

View File

@ -16,7 +16,7 @@ import (
"github.com/gogs/gogs/pkg/setting" "github.com/gogs/gogs/pkg/setting"
) )
const APP_VER = "0.11.76.1204" const APP_VER = "0.11.77.1206"
func init() { func init() {
setting.AppVer = APP_VER setting.AppVer = APP_VER

30
pkg/context/user.go Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2018 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 context
import (
"gopkg.in/macaron.v1"
"github.com/gogs/gogs/models"
"github.com/gogs/gogs/models/errors"
)
// ParamsUser is the wrapper type of the target user defined by URL parameter, namely ':username'.
type ParamsUser struct {
*models.User
}
// InjectParamsUser returns a handler that retrieves target user based on URL parameter ':username',
// and injects it as *ParamsUser.
func InjectParamsUser() macaron.Handler {
return func(c *Context) {
user, err := models.GetUserByName(c.Params(":username"))
if err != nil {
c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err)
return
}
c.Map(&ParamsUser{user})
}
}

View File

@ -347,6 +347,9 @@ footer .ui.language .menu {
.hide { .hide {
display: none; display: none;
} }
.display.inline {
display: inline;
}
.center { .center {
text-align: center; text-align: center;
} }
@ -2934,6 +2937,9 @@ footer .ui.language .menu {
margin-top: 5px; margin-top: 5px;
margin-right: 8px; margin-right: 8px;
} }
.user.profile .ui.card .profile-avatar {
height: 287px;
}
.user.profile .ui.card .header { .user.profile .ui.card .header {
word-break: break-all; word-break: break-all;
} }

View File

@ -9,11 +9,11 @@ function initCommentPreviewTab($form) {
$tabMenu.find('.item[data-tab="' + $tabMenu.data('preview') + '"]').click(function () { $tabMenu.find('.item[data-tab="' + $tabMenu.data('preview') + '"]').click(function () {
var $this = $(this); var $this = $(this);
$.post($this.data('url'), { $.post($this.data('url'), {
"_csrf": csrf, "_csrf": csrf,
"mode": "gfm", "mode": "gfm",
"context": $this.data('context'), "context": $this.data('context'),
"text": $form.find('.tab.segment[data-tab="' + $tabMenu.data('write') + '"] textarea').val() "text": $form.find('.tab.segment[data-tab="' + $tabMenu.data('write') + '"] textarea').val()
}, },
function (data) { function (data) {
var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]'); var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]');
$previewPanel.html(data); $previewPanel.html(data);
@ -39,11 +39,11 @@ function initEditPreviewTab($form) {
$previewTab.click(function () { $previewTab.click(function () {
var $this = $(this); var $this = $(this);
$.post($this.data('url'), { $.post($this.data('url'), {
"_csrf": csrf, "_csrf": csrf,
"mode": "gfm", "mode": "gfm",
"context": $this.data('context'), "context": $this.data('context'),
"text": $form.find('.tab.segment[data-tab="' + $tabMenu.data('write') + '"] textarea').val() "text": $form.find('.tab.segment[data-tab="' + $tabMenu.data('write') + '"] textarea').val()
}, },
function (data) { function (data) {
var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]'); var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]');
$previewPanel.html(data); $previewPanel.html(data);
@ -63,9 +63,9 @@ function initEditDiffTab($form) {
$tabMenu.find('.item[data-tab="' + $tabMenu.data('diff') + '"]').click(function () { $tabMenu.find('.item[data-tab="' + $tabMenu.data('diff') + '"]').click(function () {
var $this = $(this); var $this = $(this);
$.post($this.data('url'), { $.post($this.data('url'), {
"_csrf": csrf, "_csrf": csrf,
"content": $form.find('.tab.segment[data-tab="' + $tabMenu.data('write') + '"] textarea').val() "content": $form.find('.tab.segment[data-tab="' + $tabMenu.data('write') + '"] textarea').val()
}, },
function (data) { function (data) {
var $diffPreviewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('diff') + '"]'); var $diffPreviewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('diff') + '"]');
$diffPreviewPanel.html(data); $diffPreviewPanel.html(data);
@ -221,7 +221,7 @@ function initRepository() {
window.location.href = $choice.data('url'); window.location.href = $choice.data('url');
console.log($choice.data('url')) console.log($choice.data('url'))
}, },
message: {noResults: $dropdown.data('no-results')} message: { noResults: $dropdown.data('no-results') }
}); });
} }
@ -346,9 +346,9 @@ function initRepository() {
} }
$.post($(this).data('update-url'), { $.post($(this).data('update-url'), {
"_csrf": csrf, "_csrf": csrf,
"title": $editInput.val() "title": $editInput.val()
}, },
function (data) { function (data) {
$editInput.val(data.title); $editInput.val(data.title);
$issueTitle.text(data.title); $issueTitle.text(data.title);
@ -390,10 +390,10 @@ function initRepository() {
$editContentZone.hide(); $editContentZone.hide();
$.post($editContentZone.data('update-url'), { $.post($editContentZone.data('update-url'), {
"_csrf": csrf, "_csrf": csrf,
"content": $textarea.val(), "content": $textarea.val(),
"context": $editContentZone.data('context') "context": $editContentZone.data('context')
}, },
function (data) { function (data) {
if (data.length == 0) { if (data.length == 0) {
$renderContent.html($('#no-content').html()); $renderContent.html($('#no-content').html());
@ -500,14 +500,14 @@ function initRepository() {
initFilterSearchDropdown('.choose.branch .dropdown'); initFilterSearchDropdown('.choose.branch .dropdown');
} }
if ($('.repository.view.pull').length > 0) { if ($('.repository.view.pull').length > 0) {
$('.comment.merge.box input[name=merge_style]').change(function () { $('.comment.merge.box input[name=merge_style]').change(function () {
if ($(this).val() === 'create_merge_commit') { if ($(this).val() === 'create_merge_commit') {
$('.commit.description.field').show(); $('.commit.description.field').show();
} else { } else {
$('.commit.description.field').hide(); $('.commit.description.field').hide();
} }
}) })
} }
} }
function initWikiForm() { function initWikiForm() {
@ -521,11 +521,11 @@ function initWikiForm() {
setTimeout(function () { setTimeout(function () {
// FIXME: still send render request when return back to edit mode // FIXME: still send render request when return back to edit mode
$.post($editArea.data('url'), { $.post($editArea.data('url'), {
"_csrf": csrf, "_csrf": csrf,
"mode": "gfm", "mode": "gfm",
"context": $editArea.data('context'), "context": $editArea.data('context'),
"text": plainText "text": plainText
}, },
function (data) { function (data) {
preview.innerHTML = '<div class="markdown">' + data + '</div>'; preview.innerHTML = '<div class="markdown">' + data + '</div>';
emojify.run($('.editor-preview')[0]); emojify.run($('.editor-preview')[0]);
@ -603,11 +603,11 @@ function setSimpleMDE($editArea) {
setTimeout(function () { setTimeout(function () {
// FIXME: still send render request when return back to edit mode // FIXME: still send render request when return back to edit mode
$.post($editArea.data('url'), { $.post($editArea.data('url'), {
"_csrf": csrf, "_csrf": csrf,
"mode": "gfm", "mode": "gfm",
"context": $editArea.data('context'), "context": $editArea.data('context'),
"text": plainText "text": plainText
}, },
function (data) { function (data) {
preview.innerHTML = '<div class="markdown">' + data + '</div>'; preview.innerHTML = '<div class="markdown">' + data + '</div>';
emojify.run($('.editor-preview')[0]); emojify.run($('.editor-preview')[0]);
@ -652,10 +652,10 @@ function initEditor() {
$('.js-quick-pull-choice-option').change(function () { $('.js-quick-pull-choice-option').change(function () {
if ($(this).val() == 'commit-to-new-branch') { if ($(this).val() == 'commit-to-new-branch') {
$('.quick-pull-branch-name').show(); $('.quick-pull-branch-name').show();
$('.quick-pull-branch-name input').prop('required',true); $('.quick-pull-branch-name input').prop('required', true);
} else { } else {
$('.quick-pull-branch-name').hide(); $('.quick-pull-branch-name').hide();
$('.quick-pull-branch-name input').prop('required',false); $('.quick-pull-branch-name input').prop('required', false);
} }
}); });
@ -705,7 +705,7 @@ function initEditor() {
var tree_path = parts.join('/'); var tree_path = parts.join('/');
$('#tree_path').val(tree_path); $('#tree_path').val(tree_path);
$('#preview-tab').data('context', $('#preview-tab').data('root-context') + tree_path.substring(0, tree_path.lastIndexOf("/")+1)); $('#preview-tab').data('context', $('#preview-tab').data('root-context') + tree_path.substring(0, tree_path.lastIndexOf("/") + 1));
}).trigger('keyup'); }).trigger('keyup');
var $editArea = $('.repository.editor textarea#edit_area'); var $editArea = $('.repository.editor textarea#edit_area');
@ -775,7 +775,7 @@ function initEditor() {
value = value.split('/'); value = value.split('/');
value = value[value.length - 1]; value = value[value.length - 1];
$.getJSON($editFilename.data('ec-url-prefix')+value, function(editorconfig) { $.getJSON($editFilename.data('ec-url-prefix') + value, function (editorconfig) {
if (editorconfig.indent_style === 'tab') { if (editorconfig.indent_style === 'tab') {
codeMirrorEditor.setOption("indentWithTabs", true); codeMirrorEditor.setOption("indentWithTabs", true);
codeMirrorEditor.setOption('extraKeys', {}); codeMirrorEditor.setOption('extraKeys', {});
@ -785,7 +785,7 @@ function initEditor() {
// - https://github.com/codemirror/CodeMirror/issues/988 // - https://github.com/codemirror/CodeMirror/issues/988
// - https://codemirror.net/doc/manual.html#keymaps // - https://codemirror.net/doc/manual.html#keymaps
codeMirrorEditor.setOption('extraKeys', { codeMirrorEditor.setOption('extraKeys', {
Tab: function(cm) { Tab: function (cm) {
var spaces = Array(parseInt(cm.getOption("indentUnit")) + 1).join(" "); var spaces = Array(parseInt(cm.getOption("indentUnit")) + 1).join(" ");
cm.replaceSelection(spaces); cm.replaceSelection(spaces);
} }
@ -1131,7 +1131,7 @@ function initWebhookSettings() {
$($(this).data('target') + ' .nohighlight').each(function () { $($(this).data('target') + ' .nohighlight').each(function () {
var $this = $(this); var $this = $(this);
$this.removeClass('nohighlight'); $this.removeClass('nohighlight');
setTimeout(function(){ hljs.highlightBlock($this[0]) }, 500); setTimeout(function () { hljs.highlightBlock($this[0]) }, 500);
}) })
}) })
@ -1213,7 +1213,7 @@ $(document).ready(function () {
var filenameDict = {}; var filenameDict = {};
$dropzone.dropzone({ $dropzone.dropzone({
url: $dropzone.data('upload-url'), url: $dropzone.data('upload-url'),
headers: {"X-Csrf-Token": csrf}, headers: { "X-Csrf-Token": csrf },
maxFiles: $dropzone.data('max-file'), maxFiles: $dropzone.data('max-file'),
maxFilesize: $dropzone.data('max-size'), maxFilesize: $dropzone.data('max-size'),
acceptedFiles: ($dropzone.data('accepts') === '*/*') ? null : $dropzone.data('accepts'), acceptedFiles: ($dropzone.data('accepts') === '*/*') ? null : $dropzone.data('accepts'),
@ -1336,6 +1336,10 @@ $(document).ready(function () {
window.location.href = $this.data('done-url'); window.location.href = $this.data('done-url');
}); });
}); });
// To make arbitrary form element to behave like a submit button
$('.submit-button').click(function () {
$($(this).data('form')).submit();
});
// Check or select on option to enable/disable target region // Check or select on option to enable/disable target region
$('.enable-system').change(function () { $('.enable-system').change(function () {
@ -1459,7 +1463,7 @@ $(function () {
$('form').areYouSure(); $('form').areYouSure();
}); });
// getByteLen counts bytes in a string's UTF-8 representation. // getByteLen counts bytes in a string's UTF-8 representation.
function getByteLen(normalVal) { function getByteLen(normalVal) {
// Force string type // Force string type
normalVal = String(normalVal); normalVal = String(normalVal);
@ -1467,19 +1471,19 @@ function getByteLen(normalVal) {
var byteLen = 0; var byteLen = 0;
for (var i = 0; i < normalVal.length; i++) { for (var i = 0; i < normalVal.length; i++) {
var c = normalVal.charCodeAt(i); var c = normalVal.charCodeAt(i);
byteLen += c < (1 << 7) ? 1 : byteLen += c < (1 << 7) ? 1 :
c < (1 << 11) ? 2 : c < (1 << 11) ? 2 :
c < (1 << 16) ? 3 : c < (1 << 16) ? 3 :
c < (1 << 21) ? 4 : c < (1 << 21) ? 4 :
c < (1 << 26) ? 5 : c < (1 << 26) ? 5 :
c < (1 << 31) ? 6 : Number.NaN; c < (1 << 31) ? 6 : Number.NaN;
} }
return byteLen; return byteLen;
} }
function showMessageMaxLength(maxLen, textElemId, counterId) { function showMessageMaxLength(maxLen, textElemId, counterId) {
var $msg = $('#'+textElemId); var $msg = $('#' + textElemId);
$('#'+counterId).html(maxLen - getByteLen($msg.val())); $('#' + counterId).html(maxLen - getByteLen($msg.val()));
var onMessageKey = function (e) { var onMessageKey = function (e) {
var $msg = $(this); var $msg = $(this);
@ -1492,7 +1496,7 @@ function showMessageMaxLength(maxLen, textElemId, counterId) {
remainder = 0; remainder = 0;
} }
$('#'+counterId).html(remainder); $('#' + counterId).html(remainder);
}; };
$msg.keyup(onMessageKey).keydown(onMessageKey); $msg.keyup(onMessageKey).keydown(onMessageKey);

View File

@ -384,6 +384,11 @@ footer {
.hide { .hide {
display: none; display: none;
} }
.display {
&.inline {
display: inline;
}
}
.center { .center {
text-align: center; text-align: center;
} }

View File

@ -60,6 +60,9 @@
&.profile { &.profile {
.ui.card { .ui.card {
.profile-avatar {
height: 287px;
}
.header { .header {
word-break: break-all; word-break: break-all;
} }

View File

@ -6,13 +6,11 @@ package user
import ( import (
"fmt" "fmt"
"path"
"strings" "strings"
"github.com/Unknwon/paginater" "github.com/Unknwon/paginater"
"github.com/gogs/gogs/models" "github.com/gogs/gogs/models"
"github.com/gogs/gogs/models/errors"
"github.com/gogs/gogs/pkg/context" "github.com/gogs/gogs/pkg/context"
"github.com/gogs/gogs/pkg/setting" "github.com/gogs/gogs/pkg/setting"
"github.com/gogs/gogs/pkg/tool" "github.com/gogs/gogs/pkg/tool"
@ -24,59 +22,30 @@ const (
STARS = "user/meta/stars" STARS = "user/meta/stars"
) )
func GetUserByName(c *context.Context, name string) *models.User { func Profile(c *context.Context, puser *context.ParamsUser) {
user, err := models.GetUserByName(name)
if err != nil {
c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err)
return nil
}
return user
}
// GetUserByParams returns user whose name is presented in URL paramenter.
func GetUserByParams(c *context.Context) *models.User {
return GetUserByName(c, c.Params(":username"))
}
func Profile(c *context.Context) {
uname := c.Params(":username")
// Special handle for FireFox requests favicon.ico.
if uname == "favicon.ico" {
c.ServeFile(path.Join(setting.StaticRootPath, "public/img/favicon.png"))
return
} else if strings.HasSuffix(uname, ".png") {
c.Error(404)
return
}
isShowKeys := false isShowKeys := false
if strings.HasSuffix(uname, ".keys") { if strings.HasSuffix(c.Params(":username"), ".keys") {
isShowKeys = true isShowKeys = true
} }
ctxUser := GetUserByName(c, strings.TrimSuffix(uname, ".keys"))
if c.Written() {
return
}
// Show SSH keys. // Show SSH keys.
if isShowKeys { if isShowKeys {
ShowSSHKeys(c, ctxUser.ID) ShowSSHKeys(c, puser.ID)
return return
} }
if ctxUser.IsOrganization() { if puser.IsOrganization() {
showOrgProfile(c) showOrgProfile(c)
return return
} }
c.Data["Title"] = ctxUser.DisplayName() c.Title(puser.DisplayName())
c.Data["PageIsUserProfile"] = true c.PageIs("UserProfile")
c.Data["Owner"] = ctxUser c.Data["Owner"] = puser
orgs, err := models.GetOrgsByUserID(ctxUser.ID, c.IsLogged && (c.User.IsAdmin || c.User.ID == ctxUser.ID)) orgs, err := models.GetOrgsByUserID(puser.ID, c.IsLogged && (c.User.IsAdmin || c.User.ID == puser.ID))
if err != nil { if err != nil {
c.Handle(500, "GetOrgsByUserIDDesc", err) c.ServerError("GetOrgsByUserIDDesc", err)
return return
} }
@ -86,7 +55,7 @@ func Profile(c *context.Context) {
c.Data["TabName"] = tab c.Data["TabName"] = tab
switch tab { switch tab {
case "activity": case "activity":
retrieveFeeds(c, ctxUser, -1, true) retrieveFeeds(c, puser.User, -1, true)
if c.Written() { if c.Written() {
return return
} }
@ -96,65 +65,52 @@ func Profile(c *context.Context) {
page = 1 page = 1
} }
showPrivate := c.IsLogged && (ctxUser.ID == c.User.ID || c.User.IsAdmin) showPrivate := c.IsLogged && (puser.ID == c.User.ID || c.User.IsAdmin)
c.Data["Repos"], err = models.GetUserRepositories(&models.UserRepoOptions{ c.Data["Repos"], err = models.GetUserRepositories(&models.UserRepoOptions{
UserID: ctxUser.ID, UserID: puser.ID,
Private: showPrivate, Private: showPrivate,
Page: page, Page: page,
PageSize: setting.UI.User.RepoPagingNum, PageSize: setting.UI.User.RepoPagingNum,
}) })
if err != nil { if err != nil {
c.Handle(500, "GetRepositories", err) c.ServerError("GetRepositories", err)
return return
} }
count := models.CountUserRepositories(ctxUser.ID, showPrivate) count := models.CountUserRepositories(puser.ID, showPrivate)
c.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5) c.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
} }
c.HTML(200, PROFILE) c.Success(PROFILE)
} }
func Followers(c *context.Context) { func Followers(c *context.Context, puser *context.ParamsUser) {
u := GetUserByParams(c) c.Title(puser.DisplayName())
if c.Written() { c.PageIs("Followers")
return
}
c.Data["Title"] = u.DisplayName()
c.Data["CardsTitle"] = c.Tr("user.followers") c.Data["CardsTitle"] = c.Tr("user.followers")
c.Data["PageIsFollowers"] = true c.Data["Owner"] = puser
c.Data["Owner"] = u repo.RenderUserCards(c, puser.NumFollowers, puser.GetFollowers, FOLLOWERS)
repo.RenderUserCards(c, u.NumFollowers, u.GetFollowers, FOLLOWERS)
} }
func Following(c *context.Context) { func Following(c *context.Context, puser *context.ParamsUser) {
u := GetUserByParams(c) c.Title(puser.DisplayName())
if c.Written() { c.PageIs("Following")
return
}
c.Data["Title"] = u.DisplayName()
c.Data["CardsTitle"] = c.Tr("user.following") c.Data["CardsTitle"] = c.Tr("user.following")
c.Data["PageIsFollowing"] = true c.Data["Owner"] = puser
c.Data["Owner"] = u repo.RenderUserCards(c, puser.NumFollowing, puser.GetFollowing, FOLLOWERS)
repo.RenderUserCards(c, u.NumFollowing, u.GetFollowing, FOLLOWERS)
} }
func Stars(c *context.Context) { func Stars(c *context.Context) {
} }
func Action(c *context.Context) { func Action(c *context.Context, puser *context.ParamsUser) {
u := GetUserByParams(c)
if c.Written() {
return
}
var err error var err error
switch c.Params(":action") { switch c.Params(":action") {
case "follow": case "follow":
err = models.FollowUser(c.User.ID, u.ID) err = models.FollowUser(c.UserID(), puser.ID)
case "unfollow": case "unfollow":
err = models.UnfollowUser(c.User.ID, u.ID) err = models.UnfollowUser(c.UserID(), puser.ID)
} }
if err != nil { if err != nil {
@ -164,7 +120,7 @@ func Action(c *context.Context) {
redirectTo := c.Query("redirect_to") redirectTo := c.Query("redirect_to")
if !tool.IsSameSiteURLPath(redirectTo) { if !tool.IsSameSiteURLPath(redirectTo) {
redirectTo = u.HomeLink() redirectTo = puser.HomeLink()
} }
c.Redirect(redirectTo) c.Redirect(redirectTo)
} }

View File

@ -1 +1 @@
0.11.76.1204 0.11.77.1206

View File

@ -160,9 +160,13 @@
{{end}} {{end}}
<div class="divider"></div> <div class="divider"></div>
<a class="item" href="{{AppSubURL}}/user/logout">
<i class="octicon octicon-sign-out"></i> {{.i18n.Tr "sign_out"}} <form id="logout-form" class="item" action="{{AppSubURL}}/user/logout" method="POST">
</a> {{.CSRFTokenHTML}}
<div class="submit-button" data-form="#logout-form">
<i class="octicon octicon-sign-out"></i> {{.i18n.Tr "sign_out"}}
</div>
</form>
</div><!-- end content avatar menu --> </div><!-- end content avatar menu -->
</div><!-- end dropdown avatar menu --> </div><!-- end dropdown avatar menu -->
</div><!-- end signed user right menu --> </div><!-- end signed user right menu -->

View File

@ -20,22 +20,28 @@
{{if not $.IsGuest}} {{if not $.IsGuest}}
<div class="ui right"> <div class="ui right">
<div class="ui labeled button" tabindex="0"> <form class="display inline" action="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}" method="POST">
<a class="ui basic button" href="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}"> {{$.CSRFTokenHTML}}
<i class="eye{{if not $.IsWatchingRepo}} slash outline{{end}} icon"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.unwatch"}}{{else}}{{$.i18n.Tr "repo.watch"}}{{end}} <div class="ui labeled button" tabindex="0">
</a> <button class="ui basic button">
<a class="ui basic label" href="{{.Link}}/watchers"> <i class="eye{{if not $.IsWatchingRepo}} slash outline{{end}} icon"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.unwatch"}}{{else}}{{$.i18n.Tr "repo.watch"}}{{end}}
{{.NumWatches}} </button>
</a> <a class="ui basic label" href="{{.Link}}/watchers">
</div> {{.NumWatches}}
<div class="ui labeled button" tabindex="0"> </a>
<a class="ui basic button" href="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}"> </div>
<i class="star{{if not $.IsStaringRepo}} outline{{end}} icon"></i>{{if $.IsStaringRepo}}{{$.i18n.Tr "repo.unstar"}}{{else}}{{$.i18n.Tr "repo.star"}}{{end}} </form>
</a> <form class="display inline" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}" method="POST">
<a class="ui basic label" href="{{.Link}}/stars"> {{$.CSRFTokenHTML}}
{{.NumStars}} <div class="ui labeled button" tabindex="0">
</a> <button class="ui basic button">
</div> <i class="star{{if not $.IsStaringRepo}} outline{{end}} icon"></i>{{if $.IsStaringRepo}}{{$.i18n.Tr "repo.unstar"}}{{else}}{{$.i18n.Tr "repo.star"}}{{end}}
</button>
<a class="ui basic label" href="{{.Link}}/stars">
{{.NumStars}}
</a>
</div>
</form>
{{if .CanBeForked}} {{if .CanBeForked}}
<div class="ui labeled button" tabindex="0"> <div class="ui labeled button" tabindex="0">
<a class="ui basic button {{if eq .OwnerID $.LoggedUserID}}poping up{{end}}" href="{{AppSubURL}}/repo/fork/{{.ID}}"> <a class="ui basic button {{if eq .OwnerID $.LoggedUserID}}poping up{{end}}" href="{{AppSubURL}}/repo/fork/{{.ID}}">

View File

@ -5,12 +5,12 @@
<div class="ui five wide column"> <div class="ui five wide column">
<div class="ui card"> <div class="ui card">
{{if eq .LoggedUserName .Owner.Name}} {{if eq .LoggedUserName .Owner.Name}}
<a class="image poping up" href="{{AppSubURL}}/user/settings/avatar" id="profile-avatar" data-content="{{.i18n.Tr "user.change_avatar"}}" data-variation="inverted tiny" data-position="bottom center"> <a class="profile-avatar image poping up" href="{{AppSubURL}}/user/settings/avatar" id="profile-avatar" data-content="{{.i18n.Tr "user.change_avatar"}}" data-variation="inverted tiny" data-position="bottom center">
<img src="{{AppendAvatarSize .Owner.RelAvatarLink 290}}" title="{{.Owner.Name}}"/> <img src="{{AppendAvatarSize .Owner.RelAvatarLink 287}}" title="{{.Owner.Name}}"/>
</a> </a>
{{else}} {{else}}
<span class="image"> <span class="profile-avatar image">
<img src="{{AppendAvatarSize .Owner.RelAvatarLink 290}}" title="{{.Owner.Name}}"/> <img src="{{AppendAvatarSize .Owner.RelAvatarLink 287}}" title="{{.Owner.Name}}"/>
</span> </span>
{{end}} {{end}}
<div class="content"> <div class="content">
@ -61,13 +61,23 @@
</li> </li>
{{end}} {{end}}
{{if and .IsLogged (ne .LoggedUserName .Owner.Name)}} {{if and .IsLogged (ne .LoggedUserName .Owner.Name)}}
<li class="follow"> <li class="follow">
{{if .LoggedUser.IsFollowing .Owner.ID}} {{if .LoggedUser.IsFollowing .Owner.ID}}
<a class="ui basic red button" href="{{.Link}}/action/unfollow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{.i18n.Tr "user.unfollow"}}</a> <form action="{{.Link}}/action/unfollow?redirect_to={{$.Link}}" method="POST">
{{else}} {{.CSRFTokenHTML}}
<a class="ui basic green button" href="{{.Link}}/action/follow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{.i18n.Tr "user.follow"}}</a> <button class="ui basic red button">
{{end}} <i class="octicon octicon-person"></i> {{.i18n.Tr "user.unfollow"}}
</li> </button>
</form>
{{else}}
<form action="{{.Link}}/action/follow?redirect_to={{$.Link}}" method="POST">
{{.CSRFTokenHTML}}
<button class="ui basic green button">
<i class="octicon octicon-person"></i> {{.i18n.Tr "user.follow"}}
</button>
</form>
{{end}}
</li>
{{end}} {{end}}
</ul> </ul>
</div> </div>