summaryrefslogtreecommitdiffstats
path: root/models/issue_watch.go
blob: 6144d6cafe1f29c96663bc58bf10bddaaecfb839 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2017 The Gitea 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 models

import (
	"code.gitea.io/gitea/modules/timeutil"
)

// IssueWatch is connection request for receiving issue notification.
type IssueWatch struct {
	ID          int64              `xorm:"pk autoincr"`
	UserID      int64              `xorm:"UNIQUE(watch) NOT NULL"`
	IssueID     int64              `xorm:"UNIQUE(watch) NOT NULL"`
	IsWatching  bool               `xorm:"NOT NULL"`
	CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
	UpdatedUnix timeutil.TimeStamp `xorm:"updated NOT NULL"`
}

// IssueWatchList contains IssueWatch
type IssueWatchList []*IssueWatch

// CreateOrUpdateIssueWatch set watching for a user and issue
func CreateOrUpdateIssueWatch(userID, issueID int64, isWatching bool) error {
	iw, exists, err := getIssueWatch(x, userID, issueID)
	if err != nil {
		return err
	}

	if !exists {
		iw = &IssueWatch{
			UserID:     userID,
			IssueID:    issueID,
			IsWatching: isWatching,
		}

		if _, err := x.Insert(iw); err != nil {
			return err
		}
	} else {
		iw.IsWatching = isWatching

		if _, err := x.ID(iw.ID).Cols("is_watching", "updated_unix").Update(iw); err != nil {
			return err
		}
	}
	return nil
}

// GetIssueWatch returns all IssueWatch objects from db by user and issue
// the current Web-UI need iw object for watchers AND explicit non-watchers
func GetIssueWatch(userID, issueID int64) (iw *IssueWatch, exists bool, err error) {
	return getIssueWatch(x, userID, issueID)
}

// Return watcher AND explicit non-watcher if entry in db exist
func getIssueWatch(e Engine, userID, issueID int64) (iw *IssueWatch, exists bool, err error) {
	iw = new(IssueWatch)
	exists, err = e.
		Where("user_id = ?", userID).
		And("issue_id = ?", issueID).
		Get(iw)
	return
}

// GetIssueWatchersIDs returns IDs of subscribers to a given issue id
// but avoids joining with `user` for performance reasons
// User permissions must be verified elsewhere if required
func GetIssueWatchersIDs(issueID int64) ([]int64, error) {
	ids := make([]int64, 0, 64)
	return ids, x.Table("issue_watch").
		Where("issue_id=?", issueID).
		And("is_watching = ?", true).
		Select("user_id").
		Find(&ids)
}

// GetIssueWatchers returns watchers/unwatchers of a given issue
func GetIssueWatchers(issueID int64) (IssueWatchList, error) {
	return getIssueWatchers(x, issueID)
}

func getIssueWatchers(e Engine, issueID int64) (watches IssueWatchList, err error) {
	err = e.
		Where("`issue_watch`.issue_id = ?", issueID).
		And("`issue_watch`.is_watching = ?", true).
		And("`user`.is_active = ?", true).
		And("`user`.prohibit_login = ?", false).
		Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id").
		Find(&watches)
	return
}

func removeIssueWatchersByRepoID(e Engine, userID int64, repoID int64) error {
	iw := &IssueWatch{
		IsWatching: false,
	}
	_, err := e.
		Join("INNER", "issue", "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?", repoID).
		Cols("is_watching", "updated_unix").
		Where("`issue_watch`.user_id = ?", userID).
		Update(iw)
	return err
}

// LoadWatchUsers return watching users
func (iwl IssueWatchList) LoadWatchUsers() (users UserList, err error) {
	return iwl.loadWatchUsers(x)
}

func (iwl IssueWatchList) loadWatchUsers(e Engine) (users UserList, err error) {
	if len(iwl) == 0 {
		return []*User{}, nil
	}

	var userIDs = make([]int64, 0, len(iwl))
	for _, iw := range iwl {
		if iw.IsWatching {
			userIDs = append(userIDs, iw.UserID)
		}
	}

	if len(userIDs) == 0 {
		return []*User{}, nil
	}

	err = e.In("id", userIDs).Find(&users)

	return
}