Skip to content
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
26 changes: 26 additions & 0 deletions bitbucket/notifications.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package bitbucket

import (
"context"
"fmt"

forge "github.com/git-pkgs/forge"
)

type bitbucketNotificationService struct{}

func (f *bitbucketForge) Notifications() forge.NotificationService {
return &bitbucketNotificationService{}
}

func (s *bitbucketNotificationService) List(ctx context.Context, opts forge.ListNotificationOpts) ([]forge.Notification, error) {
return nil, fmt.Errorf("listing notifications: %w", forge.ErrNotSupported)
}

func (s *bitbucketNotificationService) MarkRead(ctx context.Context, opts forge.MarkNotificationOpts) error {
return fmt.Errorf("marking notifications: %w", forge.ErrNotSupported)
}

func (s *bitbucketNotificationService) Get(ctx context.Context, id string) (*forge.Notification, error) {
return nil, fmt.Errorf("getting notification: %w", forge.ErrNotSupported)
}
28 changes: 28 additions & 0 deletions bitbucket/notifications_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package bitbucket

import (
"context"
"errors"
"testing"

forge "github.com/git-pkgs/forge"
)

func TestBitbucketNotificationsNotSupported(t *testing.T) {
f := New("test-token", nil)

_, err := f.Notifications().List(context.Background(), forge.ListNotificationOpts{})
if !errors.Is(err, forge.ErrNotSupported) {
t.Fatalf("expected ErrNotSupported, got %v", err)
}

err = f.Notifications().MarkRead(context.Background(), forge.MarkNotificationOpts{})
if !errors.Is(err, forge.ErrNotSupported) {
t.Fatalf("expected ErrNotSupported, got %v", err)
}

_, err = f.Notifications().Get(context.Background(), "1")
if !errors.Is(err, forge.ErrNotSupported) {
t.Fatalf("expected ErrNotSupported, got %v", err)
}
}
1 change: 1 addition & 0 deletions forge.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Forge interface {
Branches() BranchService
DeployKeys() DeployKeyService
Secrets() SecretService
Notifications() NotificationService
Reviews() ReviewService
}

Expand Down
16 changes: 16 additions & 0 deletions forges_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,22 @@ func (m *mockForge) Secrets() SecretService {
return &mockSecretService{}
}

func (m *mockForge) Notifications() NotificationService {
return &mockNotificationService{}
}

type mockNotificationService struct{}

func (m *mockNotificationService) List(_ context.Context, opts ListNotificationOpts) ([]Notification, error) {
return nil, nil
}
func (m *mockNotificationService) MarkRead(_ context.Context, opts MarkNotificationOpts) error {
return nil
}
func (m *mockNotificationService) Get(_ context.Context, id string) (*Notification, error) {
return nil, nil
}

func (m *mockForge) Reviews() ReviewService {
if m.reviewService != nil {
return m.reviewService
Expand Down
175 changes: 175 additions & 0 deletions gitea/notifications.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package gitea

import (
"context"
"net/http"
"strconv"
"strings"

"code.gitea.io/sdk/gitea"
forge "github.com/git-pkgs/forge"
)

type giteaNotificationService struct {
client *gitea.Client
}

func (f *giteaForge) Notifications() forge.NotificationService {
return &giteaNotificationService{client: f.client}
}

func convertGiteaSubjectType(t string) forge.NotificationSubjectType {
switch t {
case "Issue":
return forge.NotificationSubjectIssue
case "Pull":
return forge.NotificationSubjectPullRequest
case "Commit":
return forge.NotificationSubjectCommit
case "Repository":
return forge.NotificationSubjectRepository
default:
return forge.NotificationSubjectType(strings.ToLower(t))
}
}

func convertGiteaNotification(n *gitea.NotificationThread) forge.Notification {
result := forge.Notification{
ID: strconv.FormatInt(n.ID, 10),
Unread: n.Unread,
}

if n.Subject != nil {
result.Title = n.Subject.Title
result.SubjectType = convertGiteaSubjectType(string(n.Subject.Type))
result.URL = n.Subject.HTMLURL
}

if n.Repository != nil {
result.Repo = n.Repository.FullName
}

if !n.UpdatedAt.IsZero() {
result.UpdatedAt = n.UpdatedAt
}

return result
}

func (s *giteaNotificationService) List(ctx context.Context, opts forge.ListNotificationOpts) ([]forge.Notification, error) {
perPage := opts.PerPage
if perPage <= 0 {
perPage = 30
}
page := opts.Page
if page <= 0 {
page = 1
}

statuses := []gitea.NotifyStatus{}
if opts.Unread {
statuses = append(statuses, gitea.NotifyStatusUnread)
}

var all []forge.Notification

if opts.Repo != "" {
parts := strings.SplitN(opts.Repo, "/", 2)
if len(parts) == 2 {
for {
notifications, resp, err := s.client.ListRepoNotifications(parts[0], parts[1], gitea.ListNotificationOptions{
ListOptions: gitea.ListOptions{Page: page, PageSize: perPage},
Status: statuses,
})
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
return nil, forge.ErrNotFound
}
return nil, err
}
for _, n := range notifications {
all = append(all, convertGiteaNotification(n))
}
if len(notifications) < perPage || (opts.Limit > 0 && len(all) >= opts.Limit) {
break
}
page++
}
}
} else {
for {
notifications, _, err := s.client.ListNotifications(gitea.ListNotificationOptions{
ListOptions: gitea.ListOptions{Page: page, PageSize: perPage},
Status: statuses,
})
if err != nil {
return nil, err
}
for _, n := range notifications {
all = append(all, convertGiteaNotification(n))
}
if len(notifications) < perPage || (opts.Limit > 0 && len(all) >= opts.Limit) {
break
}
page++
}
}

if opts.Limit > 0 && len(all) > opts.Limit {
all = all[:opts.Limit]
}

return all, nil
}

func (s *giteaNotificationService) MarkRead(ctx context.Context, opts forge.MarkNotificationOpts) error {
if opts.ID != "" {
id, err := strconv.ParseInt(opts.ID, 10, 64)
if err != nil {
return err
}
_, resp, err := s.client.ReadNotification(id)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
return forge.ErrNotFound
}
return err
}
return nil
}

if opts.Repo != "" {
parts := strings.SplitN(opts.Repo, "/", 2)
if len(parts) == 2 {
_, resp, err := s.client.ReadRepoNotifications(parts[0], parts[1], gitea.MarkNotificationOptions{})
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
return forge.ErrNotFound
}
return err
}
return nil
}
}

_, _, err := s.client.ReadNotifications(gitea.MarkNotificationOptions{})
return err
}

func (s *giteaNotificationService) Get(ctx context.Context, id string) (*forge.Notification, error) {
nID, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return nil, err
}

n, resp, err := s.client.GetNotification(nID)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
return nil, forge.ErrNotFound
}
return nil, err
}

result := convertGiteaNotification(n)
return &result, nil
}
Loading