mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-03-26 00:53:02 -04:00
ActionUser is to keep track of pull requests posters that are permanently trusted. It has a used field to track when it was last used so records can be expired instead of accumulating forever. ActionRun has new fields to make it possible to look them up given either the pull request ID or the poster ID.
97 lines
2.6 KiB
Go
97 lines
2.6 KiB
Go
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package actions
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"forgejo.org/models/db"
|
|
"forgejo.org/modules/timeutil"
|
|
|
|
"xorm.io/builder"
|
|
)
|
|
|
|
type ActionUser struct {
|
|
ID int64 `xorm:"pk autoincr"`
|
|
UserID int64 `xorm:"INDEX UNIQUE(action_user_index) REFERENCES(user, id)"`
|
|
RepoID int64 `xorm:"INDEX UNIQUE(action_user_index) REFERENCES(repository, id)"`
|
|
|
|
TrustedWithPullRequests bool
|
|
|
|
LastAccess timeutil.TimeStamp `xorm:"INDEX"`
|
|
}
|
|
|
|
func init() {
|
|
db.RegisterModel(new(ActionUser))
|
|
}
|
|
|
|
type ErrUserNotExist struct {
|
|
UserID int64
|
|
RepoID int64
|
|
}
|
|
|
|
func IsErrUserNotExist(err error) bool {
|
|
_, ok := err.(ErrUserNotExist)
|
|
return ok
|
|
}
|
|
|
|
func (err ErrUserNotExist) Error() string {
|
|
return fmt.Sprintf("ActionUser does not exist [user_id: %d, repo_id: %d]", err.UserID, err.RepoID)
|
|
}
|
|
|
|
func InsertActionUser(ctx context.Context, user *ActionUser) error {
|
|
user.LastAccess = timeutil.TimeStampNow()
|
|
return db.Insert(ctx, user)
|
|
}
|
|
|
|
func DeleteActionUserByUserIDAndRepoID(ctx context.Context, userID, repoID int64) error {
|
|
_, err := db.GetEngine(ctx).Table(&ActionUser{}).Where("user_id=? AND repo_id=?", userID, repoID).Delete()
|
|
return err
|
|
}
|
|
|
|
var updateFrequency = 24 * time.Hour
|
|
|
|
func MaybeUpdateAccess(ctx context.Context, user *ActionUser) error {
|
|
// Keep track of the last time the record was accessed to identify which one
|
|
// are never accessed so they can be removed eventually. But only every updateFrequency
|
|
// to not stress the underlying database.
|
|
if timeutil.TimeStampNow() > user.LastAccess.AddDuration(updateFrequency) {
|
|
user.LastAccess = timeutil.TimeStampNow()
|
|
if _, err := db.GetEngine(ctx).ID(user.ID).Cols("last_access").Update(user); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func GetActionUserByUserIDAndRepoID(ctx context.Context, userID, repoID int64) (*ActionUser, error) {
|
|
user := new(ActionUser)
|
|
has, err := db.GetEngine(ctx).Where("user_id=? AND repo_id=?", userID, repoID).Get(user)
|
|
if err != nil {
|
|
return nil, err
|
|
} else if !has {
|
|
return nil, ErrUserNotExist{userID, repoID}
|
|
}
|
|
return user, nil
|
|
}
|
|
|
|
func GetActionUserByUserIDAndRepoIDAndUpdateAccess(ctx context.Context, userID, repoID int64) (*ActionUser, error) {
|
|
user, err := GetActionUserByUserIDAndRepoID(ctx, userID, repoID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return user, MaybeUpdateAccess(ctx, user)
|
|
}
|
|
|
|
var expire = 3 * 30 * 24 * time.Hour
|
|
|
|
func RevokeInactiveActionUser(ctx context.Context) error {
|
|
olderThan := timeutil.TimeStampNow().AddDuration(-expire)
|
|
|
|
_, err := db.GetEngine(ctx).Where(builder.Lt{"last_access": olderThan}).Delete(&ActionUser{})
|
|
return err
|
|
}
|