634 lines
24 KiB
Go
634 lines
24 KiB
Go
package forge
|
|
|
|
import (
|
|
"context"
|
|
"iter"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
|
|
"dappco.re/go/core/forge/types"
|
|
)
|
|
|
|
// UserService handles user operations.
|
|
//
|
|
// Usage:
|
|
//
|
|
// f := forge.NewForge("https://forge.lthn.ai", "token")
|
|
// _, err := f.Users.GetCurrent(ctx)
|
|
type UserService struct {
|
|
Resource[types.User, struct{}, struct{}]
|
|
}
|
|
|
|
// UserSearchOptions controls filtering for user searches.
|
|
type UserSearchOptions struct {
|
|
UID int64
|
|
}
|
|
|
|
func (o UserSearchOptions) queryParams() map[string]string {
|
|
if o.UID == 0 {
|
|
return nil
|
|
}
|
|
return map[string]string{
|
|
"uid": strconv.FormatInt(o.UID, 10),
|
|
}
|
|
}
|
|
|
|
// UserKeyListOptions controls filtering for authenticated user public key listings.
|
|
type UserKeyListOptions struct {
|
|
Fingerprint string
|
|
}
|
|
|
|
func (o UserKeyListOptions) queryParams() map[string]string {
|
|
if o.Fingerprint == "" {
|
|
return nil
|
|
}
|
|
return map[string]string{
|
|
"fingerprint": o.Fingerprint,
|
|
}
|
|
}
|
|
|
|
type userSearchResults struct {
|
|
Data []*types.User `json:"data,omitempty"`
|
|
OK bool `json:"ok,omitempty"`
|
|
}
|
|
|
|
func newUserService(c *Client) *UserService {
|
|
return &UserService{
|
|
Resource: *NewResource[types.User, struct{}, struct{}](
|
|
c, "/api/v1/users/{username}",
|
|
),
|
|
}
|
|
}
|
|
|
|
// GetCurrent returns the authenticated user.
|
|
func (s *UserService) GetCurrent(ctx context.Context) (*types.User, error) {
|
|
var out types.User
|
|
if err := s.client.Get(ctx, "/api/v1/user", &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// GetSettings returns the authenticated user's settings.
|
|
func (s *UserService) GetSettings(ctx context.Context) (*types.UserSettings, error) {
|
|
var out types.UserSettings
|
|
if err := s.client.Get(ctx, "/api/v1/user/settings", &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// UpdateSettings updates the authenticated user's settings.
|
|
func (s *UserService) UpdateSettings(ctx context.Context, opts *types.UserSettingsOptions) (*types.UserSettings, error) {
|
|
var out types.UserSettings
|
|
if err := s.client.Patch(ctx, "/api/v1/user/settings", opts, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// GetQuota returns the authenticated user's quota information.
|
|
func (s *UserService) GetQuota(ctx context.Context) (*types.QuotaInfo, error) {
|
|
var out types.QuotaInfo
|
|
if err := s.client.Get(ctx, "/api/v1/user/quota", &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// SearchUsersPage returns a single page of users matching the search filters.
|
|
func (s *UserService) SearchUsersPage(ctx context.Context, query string, pageOpts ListOptions, filters ...UserSearchOptions) (*PagedResult[types.User], error) {
|
|
if pageOpts.Page < 1 {
|
|
pageOpts.Page = 1
|
|
}
|
|
if pageOpts.Limit < 1 {
|
|
pageOpts.Limit = 50
|
|
}
|
|
|
|
u, err := url.Parse("/api/v1/users/search")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
q := u.Query()
|
|
q.Set("q", query)
|
|
for _, filter := range filters {
|
|
for key, value := range filter.queryParams() {
|
|
q.Set(key, value)
|
|
}
|
|
}
|
|
q.Set("page", strconv.Itoa(pageOpts.Page))
|
|
q.Set("limit", strconv.Itoa(pageOpts.Limit))
|
|
u.RawQuery = q.Encode()
|
|
|
|
var out userSearchResults
|
|
resp, err := s.client.doJSON(ctx, http.MethodGet, u.String(), nil, &out)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
totalCount, _ := strconv.Atoi(resp.Header.Get("X-Total-Count"))
|
|
items := make([]types.User, 0, len(out.Data))
|
|
for _, user := range out.Data {
|
|
if user != nil {
|
|
items = append(items, *user)
|
|
}
|
|
}
|
|
|
|
return &PagedResult[types.User]{
|
|
Items: items,
|
|
TotalCount: totalCount,
|
|
Page: pageOpts.Page,
|
|
HasMore: (totalCount > 0 && (pageOpts.Page-1)*pageOpts.Limit+len(items) < totalCount) ||
|
|
(totalCount == 0 && len(items) >= pageOpts.Limit),
|
|
}, nil
|
|
}
|
|
|
|
// SearchUsers returns all users matching the search filters.
|
|
func (s *UserService) SearchUsers(ctx context.Context, query string, filters ...UserSearchOptions) ([]types.User, error) {
|
|
var all []types.User
|
|
page := 1
|
|
|
|
for {
|
|
result, err := s.SearchUsersPage(ctx, query, ListOptions{Page: page, Limit: 50}, filters...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
all = append(all, result.Items...)
|
|
if !result.HasMore {
|
|
break
|
|
}
|
|
page++
|
|
}
|
|
|
|
return all, nil
|
|
}
|
|
|
|
// IterSearchUsers returns an iterator over users matching the search filters.
|
|
func (s *UserService) IterSearchUsers(ctx context.Context, query string, filters ...UserSearchOptions) iter.Seq2[types.User, error] {
|
|
return func(yield func(types.User, error) bool) {
|
|
page := 1
|
|
for {
|
|
result, err := s.SearchUsersPage(ctx, query, ListOptions{Page: page, Limit: 50}, filters...)
|
|
if err != nil {
|
|
yield(*new(types.User), err)
|
|
return
|
|
}
|
|
for _, item := range result.Items {
|
|
if !yield(item, nil) {
|
|
return
|
|
}
|
|
}
|
|
if !result.HasMore {
|
|
break
|
|
}
|
|
page++
|
|
}
|
|
}
|
|
}
|
|
|
|
// ListQuotaArtifacts returns all artifacts affecting the authenticated user's quota.
|
|
func (s *UserService) ListQuotaArtifacts(ctx context.Context) ([]types.QuotaUsedArtifact, error) {
|
|
return ListAll[types.QuotaUsedArtifact](ctx, s.client, "/api/v1/user/quota/artifacts", nil)
|
|
}
|
|
|
|
// IterQuotaArtifacts returns an iterator over all artifacts affecting the authenticated user's quota.
|
|
func (s *UserService) IterQuotaArtifacts(ctx context.Context) iter.Seq2[types.QuotaUsedArtifact, error] {
|
|
return ListIter[types.QuotaUsedArtifact](ctx, s.client, "/api/v1/user/quota/artifacts", nil)
|
|
}
|
|
|
|
// ListQuotaAttachments returns all attachments affecting the authenticated user's quota.
|
|
func (s *UserService) ListQuotaAttachments(ctx context.Context) ([]types.QuotaUsedAttachment, error) {
|
|
return ListAll[types.QuotaUsedAttachment](ctx, s.client, "/api/v1/user/quota/attachments", nil)
|
|
}
|
|
|
|
// IterQuotaAttachments returns an iterator over all attachments affecting the authenticated user's quota.
|
|
func (s *UserService) IterQuotaAttachments(ctx context.Context) iter.Seq2[types.QuotaUsedAttachment, error] {
|
|
return ListIter[types.QuotaUsedAttachment](ctx, s.client, "/api/v1/user/quota/attachments", nil)
|
|
}
|
|
|
|
// ListQuotaPackages returns all packages affecting the authenticated user's quota.
|
|
func (s *UserService) ListQuotaPackages(ctx context.Context) ([]types.QuotaUsedPackage, error) {
|
|
return ListAll[types.QuotaUsedPackage](ctx, s.client, "/api/v1/user/quota/packages", nil)
|
|
}
|
|
|
|
// IterQuotaPackages returns an iterator over all packages affecting the authenticated user's quota.
|
|
func (s *UserService) IterQuotaPackages(ctx context.Context) iter.Seq2[types.QuotaUsedPackage, error] {
|
|
return ListIter[types.QuotaUsedPackage](ctx, s.client, "/api/v1/user/quota/packages", nil)
|
|
}
|
|
|
|
// ListEmails returns all email addresses for the authenticated user.
|
|
func (s *UserService) ListEmails(ctx context.Context) ([]types.Email, error) {
|
|
return ListAll[types.Email](ctx, s.client, "/api/v1/user/emails", nil)
|
|
}
|
|
|
|
// IterEmails returns an iterator over all email addresses for the authenticated user.
|
|
func (s *UserService) IterEmails(ctx context.Context) iter.Seq2[types.Email, error] {
|
|
return ListIter[types.Email](ctx, s.client, "/api/v1/user/emails", nil)
|
|
}
|
|
|
|
// AddEmails adds email addresses for the authenticated user.
|
|
func (s *UserService) AddEmails(ctx context.Context, emails ...string) ([]types.Email, error) {
|
|
var out []types.Email
|
|
if err := s.client.Post(ctx, "/api/v1/user/emails", types.CreateEmailOption{Emails: emails}, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// DeleteEmails deletes email addresses for the authenticated user.
|
|
func (s *UserService) DeleteEmails(ctx context.Context, emails ...string) error {
|
|
return s.client.DeleteWithBody(ctx, "/api/v1/user/emails", types.DeleteEmailOption{Emails: emails})
|
|
}
|
|
|
|
// UpdateAvatar updates the authenticated user's avatar.
|
|
func (s *UserService) UpdateAvatar(ctx context.Context, opts *types.UpdateUserAvatarOption) error {
|
|
return s.client.Post(ctx, "/api/v1/user/avatar", opts, nil)
|
|
}
|
|
|
|
// DeleteAvatar deletes the authenticated user's avatar.
|
|
func (s *UserService) DeleteAvatar(ctx context.Context) error {
|
|
return s.client.Delete(ctx, "/api/v1/user/avatar")
|
|
}
|
|
|
|
// ListKeys returns all public keys owned by the authenticated user.
|
|
func (s *UserService) ListKeys(ctx context.Context, filters ...UserKeyListOptions) ([]types.PublicKey, error) {
|
|
query := make(map[string]string, len(filters))
|
|
for _, filter := range filters {
|
|
for key, value := range filter.queryParams() {
|
|
query[key] = value
|
|
}
|
|
}
|
|
if len(query) == 0 {
|
|
query = nil
|
|
}
|
|
return ListAll[types.PublicKey](ctx, s.client, "/api/v1/user/keys", query)
|
|
}
|
|
|
|
// IterKeys returns an iterator over all public keys owned by the authenticated user.
|
|
func (s *UserService) IterKeys(ctx context.Context, filters ...UserKeyListOptions) iter.Seq2[types.PublicKey, error] {
|
|
query := make(map[string]string, len(filters))
|
|
for _, filter := range filters {
|
|
for key, value := range filter.queryParams() {
|
|
query[key] = value
|
|
}
|
|
}
|
|
if len(query) == 0 {
|
|
query = nil
|
|
}
|
|
return ListIter[types.PublicKey](ctx, s.client, "/api/v1/user/keys", query)
|
|
}
|
|
|
|
// CreateKey creates a public key for the authenticated user.
|
|
func (s *UserService) CreateKey(ctx context.Context, opts *types.CreateKeyOption) (*types.PublicKey, error) {
|
|
var out types.PublicKey
|
|
if err := s.client.Post(ctx, "/api/v1/user/keys", opts, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// GetKey returns a single public key owned by the authenticated user.
|
|
func (s *UserService) GetKey(ctx context.Context, id int64) (*types.PublicKey, error) {
|
|
path := ResolvePath("/api/v1/user/keys/{id}", pathParams("id", int64String(id)))
|
|
var out types.PublicKey
|
|
if err := s.client.Get(ctx, path, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// DeleteKey removes a public key owned by the authenticated user.
|
|
func (s *UserService) DeleteKey(ctx context.Context, id int64) error {
|
|
path := ResolvePath("/api/v1/user/keys/{id}", pathParams("id", int64String(id)))
|
|
return s.client.Delete(ctx, path)
|
|
}
|
|
|
|
// ListUserKeys returns all public keys for a user.
|
|
func (s *UserService) ListUserKeys(ctx context.Context, username string, filters ...UserKeyListOptions) ([]types.PublicKey, error) {
|
|
path := ResolvePath("/api/v1/users/{username}/keys", pathParams("username", username))
|
|
query := make(map[string]string, len(filters))
|
|
for _, filter := range filters {
|
|
for key, value := range filter.queryParams() {
|
|
query[key] = value
|
|
}
|
|
}
|
|
if len(query) == 0 {
|
|
query = nil
|
|
}
|
|
return ListAll[types.PublicKey](ctx, s.client, path, query)
|
|
}
|
|
|
|
// IterUserKeys returns an iterator over all public keys for a user.
|
|
func (s *UserService) IterUserKeys(ctx context.Context, username string, filters ...UserKeyListOptions) iter.Seq2[types.PublicKey, error] {
|
|
path := ResolvePath("/api/v1/users/{username}/keys", pathParams("username", username))
|
|
query := make(map[string]string, len(filters))
|
|
for _, filter := range filters {
|
|
for key, value := range filter.queryParams() {
|
|
query[key] = value
|
|
}
|
|
}
|
|
if len(query) == 0 {
|
|
query = nil
|
|
}
|
|
return ListIter[types.PublicKey](ctx, s.client, path, query)
|
|
}
|
|
|
|
// ListGPGKeys returns all GPG keys owned by the authenticated user.
|
|
func (s *UserService) ListGPGKeys(ctx context.Context) ([]types.GPGKey, error) {
|
|
return ListAll[types.GPGKey](ctx, s.client, "/api/v1/user/gpg_keys", nil)
|
|
}
|
|
|
|
// IterGPGKeys returns an iterator over all GPG keys owned by the authenticated user.
|
|
func (s *UserService) IterGPGKeys(ctx context.Context) iter.Seq2[types.GPGKey, error] {
|
|
return ListIter[types.GPGKey](ctx, s.client, "/api/v1/user/gpg_keys", nil)
|
|
}
|
|
|
|
// CreateGPGKey adds a GPG key for the authenticated user.
|
|
func (s *UserService) CreateGPGKey(ctx context.Context, opts *types.CreateGPGKeyOption) (*types.GPGKey, error) {
|
|
var out types.GPGKey
|
|
if err := s.client.Post(ctx, "/api/v1/user/gpg_keys", opts, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// GetGPGKey returns a single GPG key owned by the authenticated user.
|
|
func (s *UserService) GetGPGKey(ctx context.Context, id int64) (*types.GPGKey, error) {
|
|
path := ResolvePath("/api/v1/user/gpg_keys/{id}", pathParams("id", int64String(id)))
|
|
var out types.GPGKey
|
|
if err := s.client.Get(ctx, path, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// DeleteGPGKey removes a GPG key owned by the authenticated user.
|
|
func (s *UserService) DeleteGPGKey(ctx context.Context, id int64) error {
|
|
path := ResolvePath("/api/v1/user/gpg_keys/{id}", pathParams("id", int64String(id)))
|
|
return s.client.Delete(ctx, path)
|
|
}
|
|
|
|
// ListUserGPGKeys returns all GPG keys for a user.
|
|
func (s *UserService) ListUserGPGKeys(ctx context.Context, username string) ([]types.GPGKey, error) {
|
|
path := ResolvePath("/api/v1/users/{username}/gpg_keys", pathParams("username", username))
|
|
return ListAll[types.GPGKey](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// IterUserGPGKeys returns an iterator over all GPG keys for a user.
|
|
func (s *UserService) IterUserGPGKeys(ctx context.Context, username string) iter.Seq2[types.GPGKey, error] {
|
|
path := ResolvePath("/api/v1/users/{username}/gpg_keys", pathParams("username", username))
|
|
return ListIter[types.GPGKey](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// GetGPGKeyVerificationToken returns the token used to verify a GPG key.
|
|
func (s *UserService) GetGPGKeyVerificationToken(ctx context.Context) (string, error) {
|
|
data, err := s.client.GetRaw(ctx, "/api/v1/user/gpg_key_token")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(data), nil
|
|
}
|
|
|
|
// VerifyGPGKey verifies a GPG key for the authenticated user.
|
|
func (s *UserService) VerifyGPGKey(ctx context.Context) (*types.GPGKey, error) {
|
|
var out types.GPGKey
|
|
if err := s.client.Post(ctx, "/api/v1/user/gpg_key_verify", nil, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// ListTokens returns all access tokens for a user.
|
|
func (s *UserService) ListTokens(ctx context.Context, username string) ([]types.AccessToken, error) {
|
|
path := ResolvePath("/api/v1/users/{username}/tokens", pathParams("username", username))
|
|
return ListAll[types.AccessToken](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// IterTokens returns an iterator over all access tokens for a user.
|
|
func (s *UserService) IterTokens(ctx context.Context, username string) iter.Seq2[types.AccessToken, error] {
|
|
path := ResolvePath("/api/v1/users/{username}/tokens", pathParams("username", username))
|
|
return ListIter[types.AccessToken](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// CreateToken creates an access token for a user.
|
|
func (s *UserService) CreateToken(ctx context.Context, username string, opts *types.CreateAccessTokenOption) (*types.AccessToken, error) {
|
|
path := ResolvePath("/api/v1/users/{username}/tokens", pathParams("username", username))
|
|
var out types.AccessToken
|
|
if err := s.client.Post(ctx, path, opts, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// DeleteToken deletes an access token for a user.
|
|
func (s *UserService) DeleteToken(ctx context.Context, username, token string) error {
|
|
path := ResolvePath("/api/v1/users/{username}/tokens/{token}", pathParams("username", username, "token", token))
|
|
return s.client.Delete(ctx, path)
|
|
}
|
|
|
|
// ListOAuth2Applications returns all OAuth2 applications owned by the authenticated user.
|
|
func (s *UserService) ListOAuth2Applications(ctx context.Context) ([]types.OAuth2Application, error) {
|
|
return ListAll[types.OAuth2Application](ctx, s.client, "/api/v1/user/applications/oauth2", nil)
|
|
}
|
|
|
|
// IterOAuth2Applications returns an iterator over all OAuth2 applications owned by the authenticated user.
|
|
func (s *UserService) IterOAuth2Applications(ctx context.Context) iter.Seq2[types.OAuth2Application, error] {
|
|
return ListIter[types.OAuth2Application](ctx, s.client, "/api/v1/user/applications/oauth2", nil)
|
|
}
|
|
|
|
// CreateOAuth2Application creates a new OAuth2 application for the authenticated user.
|
|
func (s *UserService) CreateOAuth2Application(ctx context.Context, opts *types.CreateOAuth2ApplicationOptions) (*types.OAuth2Application, error) {
|
|
var out types.OAuth2Application
|
|
if err := s.client.Post(ctx, "/api/v1/user/applications/oauth2", opts, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// GetOAuth2Application returns a single OAuth2 application owned by the authenticated user.
|
|
func (s *UserService) GetOAuth2Application(ctx context.Context, id int64) (*types.OAuth2Application, error) {
|
|
path := ResolvePath("/api/v1/user/applications/oauth2/{id}", pathParams("id", int64String(id)))
|
|
var out types.OAuth2Application
|
|
if err := s.client.Get(ctx, path, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// UpdateOAuth2Application updates an OAuth2 application owned by the authenticated user.
|
|
func (s *UserService) UpdateOAuth2Application(ctx context.Context, id int64, opts *types.CreateOAuth2ApplicationOptions) (*types.OAuth2Application, error) {
|
|
path := ResolvePath("/api/v1/user/applications/oauth2/{id}", pathParams("id", int64String(id)))
|
|
var out types.OAuth2Application
|
|
if err := s.client.Patch(ctx, path, opts, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// DeleteOAuth2Application deletes an OAuth2 application owned by the authenticated user.
|
|
func (s *UserService) DeleteOAuth2Application(ctx context.Context, id int64) error {
|
|
path := ResolvePath("/api/v1/user/applications/oauth2/{id}", pathParams("id", int64String(id)))
|
|
return s.client.Delete(ctx, path)
|
|
}
|
|
|
|
// ListStopwatches returns all existing stopwatches for the authenticated user.
|
|
func (s *UserService) ListStopwatches(ctx context.Context) ([]types.StopWatch, error) {
|
|
return ListAll[types.StopWatch](ctx, s.client, "/api/v1/user/stopwatches", nil)
|
|
}
|
|
|
|
// IterStopwatches returns an iterator over all existing stopwatches for the authenticated user.
|
|
func (s *UserService) IterStopwatches(ctx context.Context) iter.Seq2[types.StopWatch, error] {
|
|
return ListIter[types.StopWatch](ctx, s.client, "/api/v1/user/stopwatches", nil)
|
|
}
|
|
|
|
// ListBlockedUsers returns all users blocked by the authenticated user.
|
|
func (s *UserService) ListBlockedUsers(ctx context.Context) ([]types.BlockedUser, error) {
|
|
return ListAll[types.BlockedUser](ctx, s.client, "/api/v1/user/list_blocked", nil)
|
|
}
|
|
|
|
// IterBlockedUsers returns an iterator over all users blocked by the authenticated user.
|
|
func (s *UserService) IterBlockedUsers(ctx context.Context) iter.Seq2[types.BlockedUser, error] {
|
|
return ListIter[types.BlockedUser](ctx, s.client, "/api/v1/user/list_blocked", nil)
|
|
}
|
|
|
|
// Block blocks a user as the authenticated user.
|
|
func (s *UserService) Block(ctx context.Context, username string) error {
|
|
path := ResolvePath("/api/v1/user/block/{username}", pathParams("username", username))
|
|
return s.client.Put(ctx, path, nil, nil)
|
|
}
|
|
|
|
// Unblock unblocks a user as the authenticated user.
|
|
func (s *UserService) Unblock(ctx context.Context, username string) error {
|
|
path := ResolvePath("/api/v1/user/unblock/{username}", pathParams("username", username))
|
|
return s.client.Put(ctx, path, nil, nil)
|
|
}
|
|
|
|
// ListMySubscriptions returns all repositories watched by the authenticated user.
|
|
func (s *UserService) ListMySubscriptions(ctx context.Context) ([]types.Repository, error) {
|
|
return ListAll[types.Repository](ctx, s.client, "/api/v1/user/subscriptions", nil)
|
|
}
|
|
|
|
// IterMySubscriptions returns an iterator over all repositories watched by the authenticated user.
|
|
func (s *UserService) IterMySubscriptions(ctx context.Context) iter.Seq2[types.Repository, error] {
|
|
return ListIter[types.Repository](ctx, s.client, "/api/v1/user/subscriptions", nil)
|
|
}
|
|
|
|
// ListMyStarred returns all repositories starred by the authenticated user.
|
|
func (s *UserService) ListMyStarred(ctx context.Context) ([]types.Repository, error) {
|
|
return ListAll[types.Repository](ctx, s.client, "/api/v1/user/starred", nil)
|
|
}
|
|
|
|
// IterMyStarred returns an iterator over all repositories starred by the authenticated user.
|
|
func (s *UserService) IterMyStarred(ctx context.Context) iter.Seq2[types.Repository, error] {
|
|
return ListIter[types.Repository](ctx, s.client, "/api/v1/user/starred", nil)
|
|
}
|
|
|
|
// ListFollowers returns all followers of a user.
|
|
func (s *UserService) ListFollowers(ctx context.Context, username string) ([]types.User, error) {
|
|
path := ResolvePath("/api/v1/users/{username}/followers", pathParams("username", username))
|
|
return ListAll[types.User](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// IterFollowers returns an iterator over all followers of a user.
|
|
func (s *UserService) IterFollowers(ctx context.Context, username string) iter.Seq2[types.User, error] {
|
|
path := ResolvePath("/api/v1/users/{username}/followers", pathParams("username", username))
|
|
return ListIter[types.User](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// ListSubscriptions returns all repositories watched by a user.
|
|
func (s *UserService) ListSubscriptions(ctx context.Context, username string) ([]types.Repository, error) {
|
|
path := ResolvePath("/api/v1/users/{username}/subscriptions", pathParams("username", username))
|
|
return ListAll[types.Repository](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// IterSubscriptions returns an iterator over all repositories watched by a user.
|
|
func (s *UserService) IterSubscriptions(ctx context.Context, username string) iter.Seq2[types.Repository, error] {
|
|
path := ResolvePath("/api/v1/users/{username}/subscriptions", pathParams("username", username))
|
|
return ListIter[types.Repository](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// ListFollowing returns all users that a user is following.
|
|
func (s *UserService) ListFollowing(ctx context.Context, username string) ([]types.User, error) {
|
|
path := ResolvePath("/api/v1/users/{username}/following", pathParams("username", username))
|
|
return ListAll[types.User](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// IterFollowing returns an iterator over all users that a user is following.
|
|
func (s *UserService) IterFollowing(ctx context.Context, username string) iter.Seq2[types.User, error] {
|
|
path := ResolvePath("/api/v1/users/{username}/following", pathParams("username", username))
|
|
return ListIter[types.User](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// Follow follows a user as the authenticated user.
|
|
func (s *UserService) Follow(ctx context.Context, username string) error {
|
|
path := ResolvePath("/api/v1/user/following/{username}", pathParams("username", username))
|
|
return s.client.Put(ctx, path, nil, nil)
|
|
}
|
|
|
|
// CheckFollowing reports whether one user is following another user.
|
|
func (s *UserService) CheckFollowing(ctx context.Context, username, target string) (bool, error) {
|
|
path := ResolvePath("/api/v1/users/{username}/following/{target}", pathParams("username", username, "target", target))
|
|
resp, err := s.client.doJSON(ctx, http.MethodGet, path, nil, nil)
|
|
if err != nil {
|
|
if IsNotFound(err) {
|
|
return false, nil
|
|
}
|
|
return false, err
|
|
}
|
|
return resp.StatusCode == http.StatusNoContent, nil
|
|
}
|
|
|
|
// Unfollow unfollows a user as the authenticated user.
|
|
func (s *UserService) Unfollow(ctx context.Context, username string) error {
|
|
path := ResolvePath("/api/v1/user/following/{username}", pathParams("username", username))
|
|
return s.client.Delete(ctx, path)
|
|
}
|
|
|
|
// ListStarred returns all repositories starred by a user.
|
|
func (s *UserService) ListStarred(ctx context.Context, username string) ([]types.Repository, error) {
|
|
path := ResolvePath("/api/v1/users/{username}/starred", pathParams("username", username))
|
|
return ListAll[types.Repository](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// IterStarred returns an iterator over all repositories starred by a user.
|
|
func (s *UserService) IterStarred(ctx context.Context, username string) iter.Seq2[types.Repository, error] {
|
|
path := ResolvePath("/api/v1/users/{username}/starred", pathParams("username", username))
|
|
return ListIter[types.Repository](ctx, s.client, path, nil)
|
|
}
|
|
|
|
// GetHeatmap returns a user's contribution heatmap data.
|
|
func (s *UserService) GetHeatmap(ctx context.Context, username string) ([]types.UserHeatmapData, error) {
|
|
path := ResolvePath("/api/v1/users/{username}/heatmap", pathParams("username", username))
|
|
var out []types.UserHeatmapData
|
|
if err := s.client.Get(ctx, path, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// Star stars a repository as the authenticated user.
|
|
func (s *UserService) Star(ctx context.Context, owner, repo string) error {
|
|
path := ResolvePath("/api/v1/user/starred/{owner}/{repo}", pathParams("owner", owner, "repo", repo))
|
|
return s.client.Put(ctx, path, nil, nil)
|
|
}
|
|
|
|
// Unstar unstars a repository as the authenticated user.
|
|
func (s *UserService) Unstar(ctx context.Context, owner, repo string) error {
|
|
path := ResolvePath("/api/v1/user/starred/{owner}/{repo}", pathParams("owner", owner, "repo", repo))
|
|
return s.client.Delete(ctx, path)
|
|
}
|
|
|
|
// CheckStarring reports whether the authenticated user is starring a repository.
|
|
func (s *UserService) CheckStarring(ctx context.Context, owner, repo string) (bool, error) {
|
|
path := ResolvePath("/api/v1/user/starred/{owner}/{repo}", pathParams("owner", owner, "repo", repo))
|
|
resp, err := s.client.doJSON(ctx, http.MethodGet, path, nil, nil)
|
|
if err != nil {
|
|
if IsNotFound(err) {
|
|
return false, nil
|
|
}
|
|
return false, err
|
|
}
|
|
return resp.StatusCode == http.StatusNoContent, nil
|
|
}
|