161 lines
3.8 KiB
Go
161 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"os/signal"
|
|
"path"
|
|
"runtime"
|
|
"syscall"
|
|
"time"
|
|
|
|
"gitea.urkob.com/mcr-swiss/gogstea/kit/config"
|
|
)
|
|
|
|
type user struct {
|
|
ID int `json:"id"`
|
|
Login string `json:"login"`
|
|
LoginName string `json:"login_name"`
|
|
SourceID int `json:"source_id"`
|
|
FullName string `json:"full_name"`
|
|
Email string `json:"email"`
|
|
AvatarURL string `json:"avatar_url"`
|
|
HTMLURL string `json:"html_url"`
|
|
Language string `json:"language"`
|
|
IsAdmin bool `json:"is_admin"`
|
|
LastLogin time.Time `json:"last_login"`
|
|
Created time.Time `json:"created"`
|
|
Restricted bool `json:"restricted"`
|
|
Active bool `json:"active"`
|
|
ProhibitLogin bool `json:"prohibit_login"`
|
|
Location string `json:"location"`
|
|
Website string `json:"website"`
|
|
Description string `json:"description"`
|
|
Visibility string `json:"visibility"`
|
|
FollowersCount int `json:"followers_count"`
|
|
FollowingCount int `json:"following_count"`
|
|
StarredReposCount int `json:"starred_repos_count"`
|
|
Username string `json:"username"`
|
|
}
|
|
|
|
func main() {
|
|
ctx, cancel := context.WithCancel(signalContext(context.Background()))
|
|
defer cancel()
|
|
|
|
cfgFile := os.Getenv("CONFIG_FILE")
|
|
if cfgFile == "" {
|
|
// Get root path
|
|
_, filename, _, _ := runtime.Caller(0)
|
|
cfgFile = path.Join(path.Dir(filename), "configs", "app.yml")
|
|
}
|
|
cfg, err := config.LoadConfig(cfgFile)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
outputFile, err := os.Create(wd + "/output.txt")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer outputFile.Close()
|
|
|
|
cli := http.DefaultClient
|
|
|
|
parsedURL, err := url.Parse(fmt.Sprintf(cfg.Gitea.URL + "/admin/users"))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, parsedURL.String(), http.NoBody)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// TODO: see how to pass the admin token if so
|
|
req.Header.Add("Authorization", "token "+cfg.Gitea.ApiKey)
|
|
req.Header.Add("Content-Type", "application/json")
|
|
resp, err := cli.Do(req)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
bts, _ := io.ReadAll(resp.Body)
|
|
|
|
panic(fmt.Errorf("%d | %s: %w", resp.StatusCode, string(bts), err))
|
|
}
|
|
|
|
bts, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
var users []user
|
|
if err := json.Unmarshal(bts, &users); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for _, u := range users {
|
|
if u.Username == "mcradmin" {
|
|
continue
|
|
}
|
|
|
|
// Delete
|
|
parsedURL, err := url.Parse(fmt.Sprintf("%s/admin/users/%s", cfg.Gitea.URL, u.Username))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, parsedURL.String(), http.NoBody)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
req.Header.Add("Authorization", "token "+cfg.Gitea.ApiKey)
|
|
req.Header.Add("Content-Type", "application/json")
|
|
resp, err := cli.Do(req)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
bts, _ := io.ReadAll(resp.Body)
|
|
|
|
if _, err := outputFile.WriteString(fmt.Sprintf("FAILED %d | %s | %d: %s\n", u.ID, u.Email, resp.StatusCode, string(bts))); err != nil {
|
|
panic(err)
|
|
}
|
|
continue
|
|
}
|
|
|
|
if _, err := outputFile.WriteString(fmt.Sprintf("DELETED %d | %s\n", u.ID, u.Email)); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func signalContext(ctx context.Context) context.Context {
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
sigs := make(chan os.Signal, 1)
|
|
signal.Notify(sigs, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
go func() {
|
|
<-sigs
|
|
signal.Stop(sigs)
|
|
close(sigs)
|
|
cancel()
|
|
}()
|
|
|
|
return ctx
|
|
}
|