code.gitea.io/gitea@v1.22.3/routers/api/v1/user/watch.go (about)

     1  // Copyright 2016 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package user
     5  
     6  import (
     7  	"errors"
     8  	"net/http"
     9  
    10  	access_model "code.gitea.io/gitea/models/perm/access"
    11  	repo_model "code.gitea.io/gitea/models/repo"
    12  	user_model "code.gitea.io/gitea/models/user"
    13  	api "code.gitea.io/gitea/modules/structs"
    14  	"code.gitea.io/gitea/routers/api/v1/utils"
    15  	"code.gitea.io/gitea/services/context"
    16  	"code.gitea.io/gitea/services/convert"
    17  )
    18  
    19  // getWatchedRepos returns the repos that the user with the specified userID is watching
    20  func getWatchedRepos(ctx *context.APIContext, user *user_model.User, private bool) ([]*api.Repository, int64, error) {
    21  	watchedRepos, total, err := repo_model.GetWatchedRepos(ctx, &repo_model.WatchedReposOptions{
    22  		ListOptions:    utils.GetListOptions(ctx),
    23  		WatcherID:      user.ID,
    24  		IncludePrivate: private,
    25  	})
    26  	if err != nil {
    27  		return nil, 0, err
    28  	}
    29  
    30  	repos := make([]*api.Repository, len(watchedRepos))
    31  	for i, watched := range watchedRepos {
    32  		permission, err := access_model.GetUserRepoPermission(ctx, watched, user)
    33  		if err != nil {
    34  			return nil, 0, err
    35  		}
    36  		repos[i] = convert.ToRepo(ctx, watched, permission)
    37  	}
    38  	return repos, total, nil
    39  }
    40  
    41  // GetWatchedRepos returns the repos that the user specified in ctx is watching
    42  func GetWatchedRepos(ctx *context.APIContext) {
    43  	// swagger:operation GET /users/{username}/subscriptions user userListSubscriptions
    44  	// ---
    45  	// summary: List the repositories watched by a user
    46  	// produces:
    47  	// - application/json
    48  	// parameters:
    49  	// - name: username
    50  	//   type: string
    51  	//   in: path
    52  	//   description: username of the user
    53  	//   required: true
    54  	// - name: page
    55  	//   in: query
    56  	//   description: page number of results to return (1-based)
    57  	//   type: integer
    58  	// - name: limit
    59  	//   in: query
    60  	//   description: page size of results
    61  	//   type: integer
    62  	// responses:
    63  	//   "200":
    64  	//     "$ref": "#/responses/RepositoryList"
    65  	//   "404":
    66  	//     "$ref": "#/responses/notFound"
    67  
    68  	private := ctx.ContextUser.ID == ctx.Doer.ID
    69  	repos, total, err := getWatchedRepos(ctx, ctx.ContextUser, private)
    70  	if err != nil {
    71  		ctx.Error(http.StatusInternalServerError, "getWatchedRepos", err)
    72  	}
    73  
    74  	ctx.SetTotalCountHeader(total)
    75  	ctx.JSON(http.StatusOK, &repos)
    76  }
    77  
    78  // GetMyWatchedRepos returns the repos that the authenticated user is watching
    79  func GetMyWatchedRepos(ctx *context.APIContext) {
    80  	// swagger:operation GET /user/subscriptions user userCurrentListSubscriptions
    81  	// ---
    82  	// summary: List repositories watched by the authenticated user
    83  	// produces:
    84  	// - application/json
    85  	// parameters:
    86  	// - name: page
    87  	//   in: query
    88  	//   description: page number of results to return (1-based)
    89  	//   type: integer
    90  	// - name: limit
    91  	//   in: query
    92  	//   description: page size of results
    93  	//   type: integer
    94  	// responses:
    95  	//   "200":
    96  	//     "$ref": "#/responses/RepositoryList"
    97  
    98  	repos, total, err := getWatchedRepos(ctx, ctx.Doer, true)
    99  	if err != nil {
   100  		ctx.Error(http.StatusInternalServerError, "getWatchedRepos", err)
   101  	}
   102  
   103  	ctx.SetTotalCountHeader(total)
   104  	ctx.JSON(http.StatusOK, &repos)
   105  }
   106  
   107  // IsWatching returns whether the authenticated user is watching the repo
   108  // specified in ctx
   109  func IsWatching(ctx *context.APIContext) {
   110  	// swagger:operation GET /repos/{owner}/{repo}/subscription repository userCurrentCheckSubscription
   111  	// ---
   112  	// summary: Check if the current user is watching a repo
   113  	// parameters:
   114  	// - name: owner
   115  	//   in: path
   116  	//   description: owner of the repo
   117  	//   type: string
   118  	//   required: true
   119  	// - name: repo
   120  	//   in: path
   121  	//   description: name of the repo
   122  	//   type: string
   123  	//   required: true
   124  	// responses:
   125  	//   "200":
   126  	//     "$ref": "#/responses/WatchInfo"
   127  	//   "404":
   128  	//     description: User is not watching this repo or repo do not exist
   129  
   130  	if repo_model.IsWatching(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) {
   131  		ctx.JSON(http.StatusOK, api.WatchInfo{
   132  			Subscribed:    true,
   133  			Ignored:       false,
   134  			Reason:        nil,
   135  			CreatedAt:     ctx.Repo.Repository.CreatedUnix.AsTime(),
   136  			URL:           subscriptionURL(ctx.Repo.Repository),
   137  			RepositoryURL: ctx.Repo.Repository.APIURL(),
   138  		})
   139  	} else {
   140  		ctx.NotFound()
   141  	}
   142  }
   143  
   144  // Watch the repo specified in ctx, as the authenticated user
   145  func Watch(ctx *context.APIContext) {
   146  	// swagger:operation PUT /repos/{owner}/{repo}/subscription repository userCurrentPutSubscription
   147  	// ---
   148  	// summary: Watch a repo
   149  	// parameters:
   150  	// - name: owner
   151  	//   in: path
   152  	//   description: owner of the repo
   153  	//   type: string
   154  	//   required: true
   155  	// - name: repo
   156  	//   in: path
   157  	//   description: name of the repo
   158  	//   type: string
   159  	//   required: true
   160  	// responses:
   161  	//   "200":
   162  	//     "$ref": "#/responses/WatchInfo"
   163  	//   "403":
   164  	//     "$ref": "#/responses/forbidden"
   165  	//   "404":
   166  	//     "$ref": "#/responses/notFound"
   167  
   168  	err := repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, true)
   169  	if err != nil {
   170  		if errors.Is(err, user_model.ErrBlockedUser) {
   171  			ctx.Error(http.StatusForbidden, "BlockedUser", err)
   172  		} else {
   173  			ctx.Error(http.StatusInternalServerError, "WatchRepo", err)
   174  		}
   175  		return
   176  	}
   177  	ctx.JSON(http.StatusOK, api.WatchInfo{
   178  		Subscribed:    true,
   179  		Ignored:       false,
   180  		Reason:        nil,
   181  		CreatedAt:     ctx.Repo.Repository.CreatedUnix.AsTime(),
   182  		URL:           subscriptionURL(ctx.Repo.Repository),
   183  		RepositoryURL: ctx.Repo.Repository.APIURL(),
   184  	})
   185  }
   186  
   187  // Unwatch the repo specified in ctx, as the authenticated user
   188  func Unwatch(ctx *context.APIContext) {
   189  	// swagger:operation DELETE /repos/{owner}/{repo}/subscription repository userCurrentDeleteSubscription
   190  	// ---
   191  	// summary: Unwatch a repo
   192  	// parameters:
   193  	// - name: owner
   194  	//   in: path
   195  	//   description: owner of the repo
   196  	//   type: string
   197  	//   required: true
   198  	// - name: repo
   199  	//   in: path
   200  	//   description: name of the repo
   201  	//   type: string
   202  	//   required: true
   203  	// responses:
   204  	//   "204":
   205  	//     "$ref": "#/responses/empty"
   206  	//   "404":
   207  	//     "$ref": "#/responses/notFound"
   208  
   209  	err := repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, false)
   210  	if err != nil {
   211  		ctx.Error(http.StatusInternalServerError, "UnwatchRepo", err)
   212  		return
   213  	}
   214  	ctx.Status(http.StatusNoContent)
   215  }
   216  
   217  // subscriptionURL returns the URL of the subscription API endpoint of a repo
   218  func subscriptionURL(repo *repo_model.Repository) string {
   219  	return repo.APIURL() + "/subscription"
   220  }