Skip to content

Notifications - Step 2 #539

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ func runWeb(ctx *cli.Context) error {

bindIgnErr := binding.BindIgnErr

m.Use(user.GetNotificationCount)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this add unnecessary overhead for endpoints like /api that will never use it? :)

Copy link
Member

@lunny lunny Dec 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^, Only UI route group need?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


// FIXME: not all routes need go through same middlewares.
// Especially some AJAX requests, we can reduce middleware number to improve performance.
// Routers.
Expand Down Expand Up @@ -578,6 +580,8 @@ func runWeb(ctx *cli.Context) error {
})
// ***** END: Repository *****

m.Get("/notifications", reqSignIn, user.Notifications)

m.Group("/api", func() {
apiv1.RegisterRoutes(m)
}, ignSignIn)
Expand Down
16 changes: 11 additions & 5 deletions models/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,20 @@ func getIssueNotification(e Engine, userID, issueID int64) (*Notification, error
}

// NotificationsForUser returns notifications for a given user and status
func NotificationsForUser(user *User, status NotificationStatus) ([]*Notification, error) {
return notificationsForUser(x, user, status)
func NotificationsForUser(user *User, status NotificationStatus, page, perPage int) ([]*Notification, error) {
return notificationsForUser(x, user, status, page, perPage)
}
func notificationsForUser(e Engine, user *User, status NotificationStatus) (notifications []*Notification, err error) {
err = e.
func notificationsForUser(e Engine, user *User, status NotificationStatus, page, perPage int) (notifications []*Notification, err error) {
sess := e.
Where("user_id = ?", user.ID).
And("status = ?", status).
OrderBy("updated_unix DESC").
OrderBy("updated_unix DESC")

if page > 0 && perPage > 0 {
sess.Limit(perPage, (page-1)*perPage)
}

err = sess.
Find(&notifications)
return
}
Expand Down
8 changes: 8 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ version = Version
page = Page
template = Template
language = Language
notifications = Notifications
create_new = Create...
user_profile_and_more = User profile and more
signed_in_as = Signed in as
Expand Down Expand Up @@ -1230,3 +1231,10 @@ default_message = Drop files here or click to upload.
invalid_input_type = You can't upload files of this type.
file_too_big = File size ({{filesize}} MB) exceeds maximum size ({{maxFilesize}} MB).
remove_file = Remove file

[notification]
notifications = Notifications
unread = Unread
read = Read
no_unread = You have no unread notifications.
no_read = You have no read notifications.
8 changes: 8 additions & 0 deletions options/locale/locale_pt-BR.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ version=Versão
page=Página
template=Template
language=Idioma
notifications = Notificações
create_new=Criar...
user_profile_and_more=Perfil do usuário e configurações
signed_in_as=Logado como
Expand Down Expand Up @@ -1197,3 +1198,10 @@ default_message=Arraste e solte arquivos aqui, ou clique para selecioná-los.
invalid_input_type=Você não pode enviar arquivos deste tipo.
file_too_big=O tamanho do arquivo ({{filesize}} MB) excede o limite máximo ({{maxFilesize}} MB).
remove_file=Remover

[notification]
notifications = Notificações
unread = Não lidas
read = Lidas
no_unread = Você não possui notificações não lidas.
no_read = Você não possui notificações lidas.
18 changes: 18 additions & 0 deletions public/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -2694,6 +2694,24 @@ footer .ui.language .menu {
.user.followers .follow .ui.button {
padding: 8px 15px;
}
.user.notification .octicon {
float: left;
font-size: 2em;
}
.user.notification .content {
float: left;
margin-left: 7px;
}
.user.notification .octicon-issue-opened,
.user.notification .octicon-git-pull-request {
color: #21ba45;
}
.user.notification .octicon-issue-closed {
color: #d01919;
}
.user.notification .octicon-git-merge {
color: #a333c8;
}
.dashboard {
padding-top: 15px;
padding-bottom: 80px;
Expand Down
21 changes: 21 additions & 0 deletions public/less/_user.less
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,25 @@
}
}
}

&.notification {
.octicon {
float: left;
font-size: 2em;
}
.content {
float: left;
margin-left: 7px;
}

.octicon-issue-opened, .octicon-git-pull-request {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't these defined somewhere already that we can reuse? (for the activity/dashboard feed)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so.

color: #21ba45;
}
.octicon-issue-closed {
color: #d01919;
}
.octicon-git-merge {
color: #a333c8;
}
}
}
81 changes: 81 additions & 0 deletions routers/user/notification.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package user

import (
"fmt"
"strings"

"github.com/Unknwon/paginater"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
)

const (
tplNotification base.TplName = "user/notification/notification"
)

// GetNotificationCount is the middleware that sets the notification count in the context
func GetNotificationCount(c *context.Context) {
if strings.HasPrefix(c.Req.URL.Path, "/api") {
return
}

if !c.IsSigned {
return
}

count, err := models.GetNotificationUnreadCount(c.User)
if err != nil {
c.Handle(500, "GetNotificationCount", err)
return
}

c.Data["NotificationUnreadCount"] = count
}

// Notifications is the notifications page
func Notifications(c *context.Context) {
var (
keyword = c.Query("q")
status models.NotificationStatus
page = c.QueryInt("page")
perPage = c.QueryInt("perPage")
)
if page < 1 {
page = 1
}
if perPage < 1 {
perPage = 20
}

switch keyword {
case "read":
status = models.NotificationStatusRead
default:
status = models.NotificationStatusUnread
}

notifications, err := models.NotificationsForUser(c.User, status, page, perPage)
if err != nil {
c.Handle(500, "ErrNotificationsForUser", err)
return
}

total, err := models.GetNotificationCount(c.User, status)
if err != nil {
c.Handle(500, "ErrGetNotificationCount", err)
return
}

title := "Notifications"
if count := len(notifications); count > 0 {
title = fmt.Sprintf("(%d) %s", count, title)
}
c.Data["Title"] = title
c.Data["Keyword"] = keyword
c.Data["Status"] = status
c.Data["Notifications"] = notifications
c.Data["Page"] = paginater.New(int(total), perPage, page, 5)
c.HTML(200, tplNotification)
}
1 change: 0 additions & 1 deletion routers/user/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const (
tplSettingsSocial base.TplName = "user/settings/social"
tplSettingsApplications base.TplName = "user/settings/applications"
tplSettingsDelete base.TplName = "user/settings/delete"
tplNotification base.TplName = "user/notification"
tplSecurity base.TplName = "user/security"
)

Expand Down
12 changes: 12 additions & 0 deletions templates/base/head.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,18 @@

{{if .IsSigned}}
<div class="right menu">
<a href="/notifications" class="ui head link jump item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted">
<span class="text">
<i class="octicon octicon-inbox"><span class="sr-only">{{.i18n.Tr "notifications"}}</span></i>

{{if .NotificationUnreadCount}}
<span class="ui red label">
{{.NotificationUnreadCount}}
</span>
{{end}}
</span>
</a>

<div class="ui dropdown head link jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted">
<span class="text">
<i class="octicon octicon-plus"><span class="sr-only">{{.i18n.Tr "create_new"}}</span></i>
Expand Down
70 changes: 70 additions & 0 deletions templates/user/notification/notification.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{{template "base/head" .}}

<div class="user notification">
<div class="ui container">
<h1 class="ui header">{{.i18n.Tr "notification.notifications"}}</h1>

<div class="ui top attached tabular menu">
<a href="/notifications?q=unread">
<div class="{{if eq .Status 1}}active{{end}} item">
{{.i18n.Tr "notification.unread"}}
{{if eq .Status 1}}
<div class="ui label">{{len .Notifications}}</div>
{{end}}
</div>
</a>
<a href="/notifications?q=read">
<div class="{{if eq .Status 2}}active{{end}} item">
{{.i18n.Tr "notification.read"}}
{{if eq .Status 2}}
<div class="ui label">{{len .Notifications}}</div>
{{end}}
</div>
</a>
</div>
<div class="ui bottom attached active tab segment">
{{if eq (len .Notifications) 0}}
{{if eq .Status 1}}
{{.i18n.Tr "notification.no_unread"}}
{{else}}
{{.i18n.Tr "notification.no_read"}}
{{end}}
{{else}}
<div class="ui relaxed divided list">
{{range $notification := .Notifications}}
{{$issue := $notification.GetIssue}}
{{$repo := $notification.GetRepo}}
{{$repoOwner := $repo.MustOwner}}

<div class="item">
<a href="{{$.AppSubUrl}}/{{$repoOwner.Name}}/{{$repo.Name}}/issues/{{$issue.Index}}">
{{if and $issue.IsPull}}
{{if $issue.IsClosed}}
<i class="octicon octicon-git-merge"></i>
{{else}}
<i class="octicon octicon-git-pull-request"></i>
{{end}}
{{else}}
{{if $issue.IsClosed}}
<i class="octicon octicon-issue-closed"></i>
{{else}}
<i class="octicon octicon-issue-opened"></i>
{{end}}
{{end}}

<div class="content">
<div class="header">{{$repoOwner.Name}}/{{$repo.Name}}</div>
<div class="description">#{{$issue.Index}} - {{$issue.Title}}</div>
</div>
</a>
</div>
{{end}}
</div>
{{end}}
</div>

{{template "base/paginate" .}}
</div>
</div>

{{template "base/footer" .}}