2017-03-31 01:11:58 +03:00
// Copyright 2017 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2017-03-31 01:11:58 +03:00
2022-06-13 12:37:59 +03:00
package issues
2017-03-19 22:54:12 +03:00
2020-01-07 18:41:35 +03:00
import (
2022-05-20 17:08:52 +03:00
"context"
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2021-12-12 18:48:20 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2020-01-07 18:41:35 +03:00
"code.gitea.io/gitea/modules/timeutil"
)
2017-03-19 22:54:12 +03:00
// IssueWatch is connection request for receiving issue notification.
type IssueWatch struct {
2019-08-15 17:46:21 +03:00
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" `
2017-03-19 22:54:12 +03:00
}
2017-03-30 02:31:47 +03:00
2021-09-19 14:49:59 +03:00
func init ( ) {
db . RegisterModel ( new ( IssueWatch ) )
}
2019-11-02 18:27:49 +03:00
// IssueWatchList contains IssueWatch
type IssueWatchList [ ] * IssueWatch
2017-03-30 02:31:47 +03:00
// CreateOrUpdateIssueWatch set watching for a user and issue
2023-09-16 17:39:12 +03:00
func CreateOrUpdateIssueWatch ( ctx context . Context , userID , issueID int64 , isWatching bool ) error {
iw , exists , err := GetIssueWatch ( ctx , userID , issueID )
2017-03-30 02:31:47 +03:00
if err != nil {
return err
}
if ! exists {
iw = & IssueWatch {
UserID : userID ,
IssueID : issueID ,
IsWatching : isWatching ,
}
2023-09-16 17:39:12 +03:00
if _ , err := db . GetEngine ( ctx ) . Insert ( iw ) ; err != nil {
2017-03-30 02:31:47 +03:00
return err
}
} else {
2017-03-30 02:59:28 +03:00
iw . IsWatching = isWatching
2023-09-16 17:39:12 +03:00
if _ , err := db . GetEngine ( ctx ) . ID ( iw . ID ) . Cols ( "is_watching" , "updated_unix" ) . Update ( iw ) ; err != nil {
2017-03-30 02:31:47 +03:00
return err
}
}
return nil
}
2020-01-07 18:41:35 +03:00
// GetIssueWatch returns all IssueWatch objects from db by user and issue
// the current Web-UI need iw object for watchers AND explicit non-watchers
2022-05-20 17:08:52 +03:00
func GetIssueWatch ( ctx context . Context , userID , issueID int64 ) ( iw * IssueWatch , exists bool , err error ) {
2017-03-30 02:31:47 +03:00
iw = new ( IssueWatch )
2022-05-20 17:08:52 +03:00
exists , err = db . GetEngine ( ctx ) .
2017-03-30 02:31:47 +03:00
Where ( "user_id = ?" , userID ) .
And ( "issue_id = ?" , issueID ) .
Get ( iw )
2022-06-20 13:02:49 +03:00
return iw , exists , err
2017-03-30 02:31:47 +03:00
}
2017-03-30 02:54:57 +03:00
2020-04-21 16:48:53 +03:00
// CheckIssueWatch check if an user is watching an issue
// it takes participants and repo watch into account
2023-09-16 17:39:12 +03:00
func CheckIssueWatch ( ctx context . Context , user * user_model . User , issue * Issue ) ( bool , error ) {
iw , exist , err := GetIssueWatch ( ctx , user . ID , issue . ID )
2020-04-21 16:48:53 +03:00
if err != nil {
return false , err
}
if exist {
return iw . IsWatching , nil
}
2023-09-16 17:39:12 +03:00
w , err := repo_model . GetWatch ( ctx , user . ID , issue . RepoID )
2020-04-21 16:48:53 +03:00
if err != nil {
return false , err
}
2021-12-12 18:48:20 +03:00
return repo_model . IsWatchMode ( w . Mode ) || IsUserParticipantsOfIssue ( user , issue ) , nil
2020-04-21 16:48:53 +03:00
}
2020-02-27 13:07:05 +03:00
// GetIssueWatchersIDs returns IDs of subscribers or explicit unsubscribers to a given issue id
2019-11-18 11:08:20 +03:00
// but avoids joining with `user` for performance reasons
// User permissions must be verified elsewhere if required
2022-05-20 17:08:52 +03:00
func GetIssueWatchersIDs ( ctx context . Context , issueID int64 , watching bool ) ( [ ] int64 , error ) {
2019-11-18 11:08:20 +03:00
ids := make ( [ ] int64 , 0 , 64 )
2022-05-20 17:08:52 +03:00
return ids , db . GetEngine ( ctx ) . Table ( "issue_watch" ) .
2019-11-18 11:08:20 +03:00
Where ( "issue_id=?" , issueID ) .
2020-02-26 09:32:22 +03:00
And ( "is_watching = ?" , watching ) .
2019-11-18 11:08:20 +03:00
Select ( "user_id" ) .
Find ( & ids )
}
2017-03-30 03:18:28 +03:00
// GetIssueWatchers returns watchers/unwatchers of a given issue
2022-05-20 17:08:52 +03:00
func GetIssueWatchers ( ctx context . Context , issueID int64 , listOptions db . ListOptions ) ( IssueWatchList , error ) {
sess := db . GetEngine ( ctx ) .
2017-09-16 03:18:25 +03:00
Where ( "`issue_watch`.issue_id = ?" , issueID ) .
2019-11-20 17:50:54 +03:00
And ( "`issue_watch`.is_watching = ?" , true ) .
2017-09-16 03:18:25 +03:00
And ( "`user`.is_active = ?" , true ) .
And ( "`user`.prohibit_login = ?" , false ) .
2020-01-24 22:00:29 +03:00
Join ( "INNER" , "`user`" , "`user`.id = `issue_watch`.user_id" )
2020-02-25 01:50:32 +03:00
if listOptions . Page != 0 {
2021-09-24 14:32:56 +03:00
sess = db . SetSessionPagination ( sess , & listOptions )
2020-02-25 01:50:32 +03:00
watches := make ( [ ] * IssueWatch , 0 , listOptions . PageSize )
return watches , sess . Find ( & watches )
2020-01-24 22:00:29 +03:00
}
2020-02-25 01:50:32 +03:00
watches := make ( [ ] * IssueWatch , 0 , 8 )
return watches , sess . Find ( & watches )
2017-03-30 02:54:57 +03:00
}
2018-06-19 22:44:33 +03:00
2021-12-15 08:39:34 +03:00
// CountIssueWatchers count watchers/unwatchers of a given issue
2022-05-20 17:08:52 +03:00
func CountIssueWatchers ( ctx context . Context , issueID int64 ) ( int64 , error ) {
return db . GetEngine ( ctx ) .
2021-12-15 08:39:34 +03:00
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" ) . Count ( new ( IssueWatch ) )
}
2022-06-13 12:37:59 +03:00
// RemoveIssueWatchersByRepoID remove issue watchers by repoID
func RemoveIssueWatchersByRepoID ( ctx context . Context , userID , repoID int64 ) error {
2022-05-20 17:08:52 +03:00
_ , err := db . GetEngine ( ctx ) .
2018-06-19 22:44:33 +03:00
Join ( "INNER" , "issue" , "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?" , repoID ) .
Where ( "`issue_watch`.user_id = ?" , userID ) .
2020-02-26 09:32:22 +03:00
Delete ( new ( IssueWatch ) )
2018-06-19 22:44:33 +03:00
return err
}