mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
223 lines
5.8 KiB
Go
223 lines
5.8 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package user
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
activities_model "github.com/hanzoai/git/models/activities"
|
|
user_model "github.com/hanzoai/git/models/user"
|
|
"github.com/hanzoai/git/routers/api/v1/utils"
|
|
"github.com/hanzoai/git/services/context"
|
|
"github.com/hanzoai/git/services/convert"
|
|
feed_service "github.com/hanzoai/git/services/feed"
|
|
)
|
|
|
|
// Search search users
|
|
func Search(ctx *context.APIContext) {
|
|
// swagger:operation GET /users/search user userSearch
|
|
// ---
|
|
// summary: Search for users
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - name: q
|
|
// in: query
|
|
// description: keyword
|
|
// type: string
|
|
// - name: uid
|
|
// in: query
|
|
// description: ID of the user to search for
|
|
// type: integer
|
|
// format: int64
|
|
// - name: page
|
|
// in: query
|
|
// description: page number of results to return (1-based)
|
|
// type: integer
|
|
// - name: limit
|
|
// in: query
|
|
// description: page size of results
|
|
// type: integer
|
|
// responses:
|
|
// "200":
|
|
// description: "SearchResults of a successful search"
|
|
// schema:
|
|
// type: object
|
|
// properties:
|
|
// ok:
|
|
// type: boolean
|
|
// data:
|
|
// type: array
|
|
// items:
|
|
// "$ref": "#/definitions/User"
|
|
|
|
listOptions := utils.GetListOptions(ctx)
|
|
|
|
uid := ctx.FormInt64("uid")
|
|
var users []*user_model.User
|
|
var maxResults int64
|
|
var err error
|
|
|
|
switch uid {
|
|
case user_model.GhostUserID:
|
|
maxResults = 1
|
|
users = []*user_model.User{user_model.NewGhostUser()}
|
|
case user_model.ActionsUserID:
|
|
maxResults = 1
|
|
users = []*user_model.User{user_model.NewActionsUser()}
|
|
default:
|
|
opts := user_model.SearchUserOptions{
|
|
Actor: ctx.Doer,
|
|
Keyword: ctx.FormTrim("q"),
|
|
UID: uid,
|
|
Types: []user_model.UserType{user_model.UserTypeIndividual},
|
|
SearchByEmail: true,
|
|
ListOptions: listOptions,
|
|
}
|
|
opts.ApplyPublicOnly(ctx.PublicOnly)
|
|
users, maxResults, err = user_model.SearchUsers(ctx, opts)
|
|
if err != nil {
|
|
ctx.JSON(http.StatusInternalServerError, map[string]any{
|
|
"ok": false,
|
|
"error": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
}
|
|
|
|
ctx.SetLinkHeader(maxResults, listOptions.PageSize)
|
|
ctx.SetTotalCountHeader(maxResults)
|
|
|
|
ctx.JSON(http.StatusOK, map[string]any{
|
|
"ok": true,
|
|
"data": convert.ToUsers(ctx, ctx.Doer, users),
|
|
})
|
|
}
|
|
|
|
// GetInfo get user's information
|
|
func GetInfo(ctx *context.APIContext) {
|
|
// swagger:operation GET /users/{username} user userGet
|
|
// ---
|
|
// summary: Get a user
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - name: username
|
|
// in: path
|
|
// description: username of the user whose data is to be listed
|
|
// type: string
|
|
// required: true
|
|
// responses:
|
|
// "200":
|
|
// "$ref": "#/responses/User"
|
|
// "404":
|
|
// "$ref": "#/responses/notFound"
|
|
|
|
if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) {
|
|
// fake ErrUserNotExist error message to not leak information about existence
|
|
ctx.APIErrorNotFound()
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusOK, convert.ToUser(ctx, ctx.ContextUser, ctx.Doer))
|
|
}
|
|
|
|
// GetAuthenticatedUser get current user's information
|
|
func GetAuthenticatedUser(ctx *context.APIContext) {
|
|
// swagger:operation GET /user user userGetCurrent
|
|
// ---
|
|
// summary: Get the authenticated user
|
|
// produces:
|
|
// - application/json
|
|
// responses:
|
|
// "200":
|
|
// "$ref": "#/responses/User"
|
|
|
|
ctx.JSON(http.StatusOK, convert.ToUser(ctx, ctx.Doer, ctx.Doer))
|
|
}
|
|
|
|
// GetUserHeatmapData is the handler to get a users heatmap
|
|
func GetUserHeatmapData(ctx *context.APIContext) {
|
|
// swagger:operation GET /users/{username}/heatmap user userGetHeatmapData
|
|
// ---
|
|
// summary: Get a user's heatmap
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - name: username
|
|
// in: path
|
|
// description: username of the user whose heatmap is to be obtained
|
|
// type: string
|
|
// required: true
|
|
// responses:
|
|
// "200":
|
|
// "$ref": "#/responses/UserHeatmapData"
|
|
// "404":
|
|
// "$ref": "#/responses/notFound"
|
|
|
|
heatmap, err := activities_model.GetUserHeatmapDataByUser(ctx, ctx.ContextUser, ctx.Doer)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusOK, heatmap)
|
|
}
|
|
|
|
func ListUserActivityFeeds(ctx *context.APIContext) {
|
|
// swagger:operation GET /users/{username}/activities/feeds user userListActivityFeeds
|
|
// ---
|
|
// summary: List a user's activity feeds
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - name: username
|
|
// in: path
|
|
// description: username of the user whose activity feeds are to be listed
|
|
// type: string
|
|
// required: true
|
|
// - name: only-performed-by
|
|
// in: query
|
|
// description: if true, only show actions performed by the requested user
|
|
// type: boolean
|
|
// - name: date
|
|
// in: query
|
|
// description: the date of the activities to be found
|
|
// type: string
|
|
// format: date
|
|
// - name: page
|
|
// in: query
|
|
// description: page number of results to return (1-based)
|
|
// type: integer
|
|
// - name: limit
|
|
// in: query
|
|
// description: page size of results
|
|
// type: integer
|
|
// responses:
|
|
// "200":
|
|
// "$ref": "#/responses/ActivityFeedsList"
|
|
// "404":
|
|
// "$ref": "#/responses/notFound"
|
|
|
|
includePrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
|
|
listOptions := utils.GetListOptions(ctx)
|
|
|
|
opts := activities_model.GetFeedsOptions{
|
|
RequestedUser: ctx.ContextUser,
|
|
Actor: ctx.Doer,
|
|
IncludePrivate: includePrivate,
|
|
OnlyPerformedBy: ctx.FormBool("only-performed-by"),
|
|
Date: ctx.FormString("date"),
|
|
ListOptions: listOptions,
|
|
}
|
|
opts.ApplyPublicOnly(ctx.PublicOnly)
|
|
|
|
feeds, count, err := feed_service.GetFeeds(ctx, opts)
|
|
if err != nil {
|
|
ctx.APIErrorInternal(err)
|
|
return
|
|
}
|
|
ctx.SetTotalCountHeader(count)
|
|
|
|
ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer))
|
|
}
|