Skip to content

Commit 79d5271

Browse files
authored
Merge pull request #539 from andreynering/notifications-step-2
Notifications - Step 2
2 parents 9d1bc9a + b354cf3 commit 79d5271

File tree

10 files changed

+233
-6
lines changed

10 files changed

+233
-6
lines changed

cmd/web.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ func runWeb(ctx *cli.Context) error {
167167

168168
bindIgnErr := binding.BindIgnErr
169169

170+
m.Use(user.GetNotificationCount)
171+
170172
// FIXME: not all routes need go through same middlewares.
171173
// Especially some AJAX requests, we can reduce middleware number to improve performance.
172174
// Routers.
@@ -577,6 +579,8 @@ func runWeb(ctx *cli.Context) error {
577579
})
578580
// ***** END: Repository *****
579581

582+
m.Get("/notifications", reqSignIn, user.Notifications)
583+
580584
m.Group("/api", func() {
581585
apiv1.RegisterRoutes(m)
582586
}, ignSignIn)

models/notification.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,20 @@ func getIssueNotification(e Engine, userID, issueID int64) (*Notification, error
182182
}
183183

184184
// NotificationsForUser returns notifications for a given user and status
185-
func NotificationsForUser(user *User, status NotificationStatus) ([]*Notification, error) {
186-
return notificationsForUser(x, user, status)
185+
func NotificationsForUser(user *User, status NotificationStatus, page, perPage int) ([]*Notification, error) {
186+
return notificationsForUser(x, user, status, page, perPage)
187187
}
188-
func notificationsForUser(e Engine, user *User, status NotificationStatus) (notifications []*Notification, err error) {
189-
err = e.
188+
func notificationsForUser(e Engine, user *User, status NotificationStatus, page, perPage int) (notifications []*Notification, err error) {
189+
sess := e.
190190
Where("user_id = ?", user.ID).
191191
And("status = ?", status).
192-
OrderBy("updated_unix DESC").
192+
OrderBy("updated_unix DESC")
193+
194+
if page > 0 && perPage > 0 {
195+
sess.Limit(perPage, (page-1)*perPage)
196+
}
197+
198+
err = sess.
193199
Find(&notifications)
194200
return
195201
}

options/locale/locale_en-US.ini

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ version = Version
1313
page = Page
1414
template = Template
1515
language = Language
16+
notifications = Notifications
1617
create_new = Create...
1718
user_profile_and_more = User profile and more
1819
signed_in_as = Signed in as
@@ -1232,3 +1233,10 @@ default_message = Drop files here or click to upload.
12321233
invalid_input_type = You can't upload files of this type.
12331234
file_too_big = File size ({{filesize}} MB) exceeds maximum size ({{maxFilesize}} MB).
12341235
remove_file = Remove file
1236+
1237+
[notification]
1238+
notifications = Notifications
1239+
unread = Unread
1240+
read = Read
1241+
no_unread = You have no unread notifications.
1242+
no_read = You have no read notifications.

options/locale/locale_pt-BR.ini

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ version=Versão
1313
page=Página
1414
template=Template
1515
language=Idioma
16+
notifications = Notificações
1617
create_new=Criar...
1718
user_profile_and_more=Perfil do usuário e configurações
1819
signed_in_as=Logado como
@@ -1197,3 +1198,10 @@ default_message=Arraste e solte arquivos aqui, ou clique para selecioná-los.
11971198
invalid_input_type=Você não pode enviar arquivos deste tipo.
11981199
file_too_big=O tamanho do arquivo ({{filesize}} MB) excede o limite máximo ({{maxFilesize}} MB).
11991200
remove_file=Remover
1201+
1202+
[notification]
1203+
notifications = Notificações
1204+
unread = Não lidas
1205+
read = Lidas
1206+
no_unread = Você não possui notificações não lidas.
1207+
no_read = Você não possui notificações lidas.

public/css/index.css

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2704,6 +2704,24 @@ footer .ui.language .menu {
27042704
.user.followers .follow .ui.button {
27052705
padding: 8px 15px;
27062706
}
2707+
.user.notification .octicon {
2708+
float: left;
2709+
font-size: 2em;
2710+
}
2711+
.user.notification .content {
2712+
float: left;
2713+
margin-left: 7px;
2714+
}
2715+
.user.notification .octicon-issue-opened,
2716+
.user.notification .octicon-git-pull-request {
2717+
color: #21ba45;
2718+
}
2719+
.user.notification .octicon-issue-closed {
2720+
color: #d01919;
2721+
}
2722+
.user.notification .octicon-git-merge {
2723+
color: #a333c8;
2724+
}
27072725
.dashboard {
27082726
padding-top: 15px;
27092727
padding-bottom: 80px;

public/less/_user.less

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,25 @@
7474
}
7575
}
7676
}
77+
78+
&.notification {
79+
.octicon {
80+
float: left;
81+
font-size: 2em;
82+
}
83+
.content {
84+
float: left;
85+
margin-left: 7px;
86+
}
87+
88+
.octicon-issue-opened, .octicon-git-pull-request {
89+
color: #21ba45;
90+
}
91+
.octicon-issue-closed {
92+
color: #d01919;
93+
}
94+
.octicon-git-merge {
95+
color: #a333c8;
96+
}
97+
}
7798
}

routers/user/notification.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package user
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/Unknwon/paginater"
8+
9+
"code.gitea.io/gitea/models"
10+
"code.gitea.io/gitea/modules/base"
11+
"code.gitea.io/gitea/modules/context"
12+
)
13+
14+
const (
15+
tplNotification base.TplName = "user/notification/notification"
16+
)
17+
18+
// GetNotificationCount is the middleware that sets the notification count in the context
19+
func GetNotificationCount(c *context.Context) {
20+
if strings.HasPrefix(c.Req.URL.Path, "/api") {
21+
return
22+
}
23+
24+
if !c.IsSigned {
25+
return
26+
}
27+
28+
count, err := models.GetNotificationUnreadCount(c.User)
29+
if err != nil {
30+
c.Handle(500, "GetNotificationCount", err)
31+
return
32+
}
33+
34+
c.Data["NotificationUnreadCount"] = count
35+
}
36+
37+
// Notifications is the notifications page
38+
func Notifications(c *context.Context) {
39+
var (
40+
keyword = c.Query("q")
41+
status models.NotificationStatus
42+
page = c.QueryInt("page")
43+
perPage = c.QueryInt("perPage")
44+
)
45+
if page < 1 {
46+
page = 1
47+
}
48+
if perPage < 1 {
49+
perPage = 20
50+
}
51+
52+
switch keyword {
53+
case "read":
54+
status = models.NotificationStatusRead
55+
default:
56+
status = models.NotificationStatusUnread
57+
}
58+
59+
notifications, err := models.NotificationsForUser(c.User, status, page, perPage)
60+
if err != nil {
61+
c.Handle(500, "ErrNotificationsForUser", err)
62+
return
63+
}
64+
65+
total, err := models.GetNotificationCount(c.User, status)
66+
if err != nil {
67+
c.Handle(500, "ErrGetNotificationCount", err)
68+
return
69+
}
70+
71+
title := "Notifications"
72+
if count := len(notifications); count > 0 {
73+
title = fmt.Sprintf("(%d) %s", count, title)
74+
}
75+
c.Data["Title"] = title
76+
c.Data["Keyword"] = keyword
77+
c.Data["Status"] = status
78+
c.Data["Notifications"] = notifications
79+
c.Data["Page"] = paginater.New(int(total), perPage, page, 5)
80+
c.HTML(200, tplNotification)
81+
}

routers/user/setting.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ const (
2929
tplSettingsSocial base.TplName = "user/settings/social"
3030
tplSettingsApplications base.TplName = "user/settings/applications"
3131
tplSettingsDelete base.TplName = "user/settings/delete"
32-
tplNotification base.TplName = "user/notification"
3332
tplSecurity base.TplName = "user/security"
3433
)
3534

templates/base/head.tmpl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,18 @@
8282

8383
{{if .IsSigned}}
8484
<div class="right menu">
85+
<a href="/notifications" class="ui head link jump item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted">
86+
<span class="text">
87+
<i class="octicon octicon-inbox"><span class="sr-only">{{.i18n.Tr "notifications"}}</span></i>
88+
89+
{{if .NotificationUnreadCount}}
90+
<span class="ui red label">
91+
{{.NotificationUnreadCount}}
92+
</span>
93+
{{end}}
94+
</span>
95+
</a>
96+
8597
<div class="ui dropdown head link jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted">
8698
<span class="text">
8799
<i class="octicon octicon-plus"><span class="sr-only">{{.i18n.Tr "create_new"}}</span></i>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{{template "base/head" .}}
2+
3+
<div class="user notification">
4+
<div class="ui container">
5+
<h1 class="ui header">{{.i18n.Tr "notification.notifications"}}</h1>
6+
7+
<div class="ui top attached tabular menu">
8+
<a href="/notifications?q=unread">
9+
<div class="{{if eq .Status 1}}active{{end}} item">
10+
{{.i18n.Tr "notification.unread"}}
11+
{{if eq .Status 1}}
12+
<div class="ui label">{{len .Notifications}}</div>
13+
{{end}}
14+
</div>
15+
</a>
16+
<a href="/notifications?q=read">
17+
<div class="{{if eq .Status 2}}active{{end}} item">
18+
{{.i18n.Tr "notification.read"}}
19+
{{if eq .Status 2}}
20+
<div class="ui label">{{len .Notifications}}</div>
21+
{{end}}
22+
</div>
23+
</a>
24+
</div>
25+
<div class="ui bottom attached active tab segment">
26+
{{if eq (len .Notifications) 0}}
27+
{{if eq .Status 1}}
28+
{{.i18n.Tr "notification.no_unread"}}
29+
{{else}}
30+
{{.i18n.Tr "notification.no_read"}}
31+
{{end}}
32+
{{else}}
33+
<div class="ui relaxed divided list">
34+
{{range $notification := .Notifications}}
35+
{{$issue := $notification.GetIssue}}
36+
{{$repo := $notification.GetRepo}}
37+
{{$repoOwner := $repo.MustOwner}}
38+
39+
<div class="item">
40+
<a href="{{$.AppSubUrl}}/{{$repoOwner.Name}}/{{$repo.Name}}/issues/{{$issue.Index}}">
41+
{{if and $issue.IsPull}}
42+
{{if $issue.IsClosed}}
43+
<i class="octicon octicon-git-merge"></i>
44+
{{else}}
45+
<i class="octicon octicon-git-pull-request"></i>
46+
{{end}}
47+
{{else}}
48+
{{if $issue.IsClosed}}
49+
<i class="octicon octicon-issue-closed"></i>
50+
{{else}}
51+
<i class="octicon octicon-issue-opened"></i>
52+
{{end}}
53+
{{end}}
54+
55+
<div class="content">
56+
<div class="header">{{$repoOwner.Name}}/{{$repo.Name}}</div>
57+
<div class="description">#{{$issue.Index}} - {{$issue.Title}}</div>
58+
</div>
59+
</a>
60+
</div>
61+
{{end}}
62+
</div>
63+
{{end}}
64+
</div>
65+
66+
{{template "base/paginate" .}}
67+
</div>
68+
</div>
69+
70+
{{template "base/footer" .}}

0 commit comments

Comments
 (0)