mirror of
https://github.com/thomiceli/opengist.git
synced 2025-01-24 07:00:32 +00:00
Merge pull request #11 from thomiceli/feature/admin-panel-changes
Settings on admin panel
This commit is contained in:
commit
47cbf5e7ef
15 changed files with 144 additions and 33 deletions
|
@ -5,9 +5,6 @@ log-level: warn
|
||||||
# If not set, uses the URL from the request
|
# If not set, uses the URL from the request
|
||||||
external-url:
|
external-url:
|
||||||
|
|
||||||
# Prevents the creation of new accounts (either `true` or `false`). Default: false
|
|
||||||
disable-signup: false
|
|
||||||
|
|
||||||
# Directory where Opengist will store its data. Default: ~/.opengist/
|
# Directory where Opengist will store its data. Default: ~/.opengist/
|
||||||
opengist-home:
|
opengist-home:
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,10 @@ var C *config
|
||||||
// Not using nested structs because the library
|
// Not using nested structs because the library
|
||||||
// doesn't support dot notation in this case sadly
|
// doesn't support dot notation in this case sadly
|
||||||
type config struct {
|
type config struct {
|
||||||
LogLevel string `yaml:"log-level"`
|
LogLevel string `yaml:"log-level"`
|
||||||
ExternalUrl string `yaml:"external-url"`
|
ExternalUrl string `yaml:"external-url"`
|
||||||
DisableSignup bool `yaml:"disable-signup"`
|
OpengistHome string `yaml:"opengist-home"`
|
||||||
OpengistHome string `yaml:"opengist-home"`
|
DBFilename string `yaml:"db-filename"`
|
||||||
DBFilename string `yaml:"db-filename"`
|
|
||||||
|
|
||||||
HttpHost string `yaml:"http.host"`
|
HttpHost string `yaml:"http.host"`
|
||||||
HttpPort string `yaml:"http.port"`
|
HttpPort string `yaml:"http.port"`
|
||||||
|
@ -46,7 +45,6 @@ func configWithDefaults() (*config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.LogLevel = "warn"
|
c.LogLevel = "warn"
|
||||||
c.DisableSignup = false
|
|
||||||
c.OpengistHome = filepath.Join(homeDir, ".opengist")
|
c.OpengistHome = filepath.Join(homeDir, ".opengist")
|
||||||
c.DBFilename = "opengist.db"
|
c.DBFilename = "opengist.db"
|
||||||
|
|
||||||
|
|
56
internal/models/admin_setting.go
Normal file
56
internal/models/admin_setting.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/mattn/go-sqlite3"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AdminSetting struct {
|
||||||
|
Key string `gorm:"uniqueIndex"`
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SettingDisableSignup = "disable-signup"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetSetting(key string) (string, error) {
|
||||||
|
var setting AdminSetting
|
||||||
|
err := db.Where("key = ?", key).First(&setting).Error
|
||||||
|
return setting.Value, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateSetting(key string, value string) error {
|
||||||
|
return db.Clauses(clause.OnConflict{
|
||||||
|
Columns: []clause.Column{{Name: "key"}}, // key colume
|
||||||
|
DoUpdates: clause.AssignmentColumns([]string{"value"}),
|
||||||
|
}).Create(&AdminSetting{
|
||||||
|
Key: key,
|
||||||
|
Value: value,
|
||||||
|
}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func setSetting(key string, value string) error {
|
||||||
|
return db.Create(&AdminSetting{Key: key, Value: value}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func initAdminSettings(settings map[string]string) error {
|
||||||
|
for key, value := range settings {
|
||||||
|
if err := setSetting(key, value); err != nil {
|
||||||
|
if !isUniqueConstraintViolation(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isUniqueConstraintViolation(err error) bool {
|
||||||
|
var sqliteErr sqlite3.Error
|
||||||
|
if errors.As(err, &sqliteErr) && sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
|
@ -17,11 +17,14 @@ func Setup(dbpath string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = db.AutoMigrate(&User{}, &SSHKey{}, &Gist{}); err != nil {
|
if err = db.AutoMigrate(&User{}, &SSHKey{}, &Gist{}, &AdminSetting{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
// Default admin setting values
|
||||||
|
return initAdminSettings(map[string]string{
|
||||||
|
SettingDisableSignup: "0",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func CountAll(table interface{}) (int64, error) {
|
func CountAll(table interface{}) (int64, error) {
|
||||||
|
|
|
@ -64,7 +64,7 @@ func adminUsers(ctx echo.Context) error {
|
||||||
return errorRes(500, "Cannot get users", err)
|
return errorRes(500, "Cannot get users", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = paginate(ctx, data, pageInt, 10, "data", "admin/users", 1); err != nil {
|
if err = paginate(ctx, data, pageInt, 10, "data", "admin-panel/users", 1); err != nil {
|
||||||
return errorRes(404, "Page not found", nil)
|
return errorRes(404, "Page not found", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ func adminGists(ctx echo.Context) error {
|
||||||
return errorRes(500, "Cannot get gists", err)
|
return errorRes(500, "Cannot get gists", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = paginate(ctx, data, pageInt, 10, "data", "admin/gists", 1); err != nil {
|
if err = paginate(ctx, data, pageInt, 10, "data", "admin-panel/gists", 1); err != nil {
|
||||||
return errorRes(404, "Page not found", nil)
|
return errorRes(404, "Page not found", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ func adminUserDelete(ctx echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
addFlash(ctx, "User has been deleted", "success")
|
addFlash(ctx, "User has been deleted", "success")
|
||||||
return redirect(ctx, "/admin/users")
|
return redirect(ctx, "/admin-panel/users")
|
||||||
}
|
}
|
||||||
|
|
||||||
func adminGistDelete(ctx echo.Context) error {
|
func adminGistDelete(ctx echo.Context) error {
|
||||||
|
@ -119,7 +119,7 @@ func adminGistDelete(ctx echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
addFlash(ctx, "Gist has been deleted", "success")
|
addFlash(ctx, "Gist has been deleted", "success")
|
||||||
return redirect(ctx, "/admin/gists")
|
return redirect(ctx, "/admin-panel/gists")
|
||||||
}
|
}
|
||||||
|
|
||||||
func adminSyncReposFromFS(ctx echo.Context) error {
|
func adminSyncReposFromFS(ctx echo.Context) error {
|
||||||
|
@ -148,7 +148,7 @@ func adminSyncReposFromFS(ctx echo.Context) error {
|
||||||
}
|
}
|
||||||
syncReposFromFS = false
|
syncReposFromFS = false
|
||||||
}()
|
}()
|
||||||
return redirect(ctx, "/admin")
|
return redirect(ctx, "/admin-panel")
|
||||||
}
|
}
|
||||||
|
|
||||||
func adminSyncReposFromDB(ctx echo.Context) error {
|
func adminSyncReposFromDB(ctx echo.Context) error {
|
||||||
|
@ -180,5 +180,18 @@ func adminSyncReposFromDB(ctx echo.Context) error {
|
||||||
syncReposFromDB = false
|
syncReposFromDB = false
|
||||||
return
|
return
|
||||||
}()
|
}()
|
||||||
return redirect(ctx, "/admin")
|
return redirect(ctx, "/admin-panel")
|
||||||
|
}
|
||||||
|
|
||||||
|
func adminSetSetting(ctx echo.Context) error {
|
||||||
|
key := ctx.FormValue("key")
|
||||||
|
value := ctx.FormValue("value")
|
||||||
|
|
||||||
|
if err := models.UpdateSetting(key, value); err != nil {
|
||||||
|
return errorRes(500, "Cannot set setting", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.JSON(200, map[string]interface{}{
|
||||||
|
"success": true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"opengist/internal/config"
|
|
||||||
"opengist/internal/models"
|
"opengist/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,7 +15,7 @@ func register(ctx echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func processRegister(ctx echo.Context) error {
|
func processRegister(ctx echo.Context) error {
|
||||||
if config.C.DisableSignup {
|
if getData(ctx, "signupDisabled") == true {
|
||||||
return errorRes(403, "Signing up is disabled", nil)
|
return errorRes(403, "Signing up is disabled", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ func Start() {
|
||||||
g1.POST("/settings/ssh-keys", sshKeysProcess, logged)
|
g1.POST("/settings/ssh-keys", sshKeysProcess, logged)
|
||||||
g1.DELETE("/settings/ssh-keys/:id", sshKeysDelete, logged)
|
g1.DELETE("/settings/ssh-keys/:id", sshKeysDelete, logged)
|
||||||
|
|
||||||
g2 := g1.Group("/admin")
|
g2 := g1.Group("/admin-panel")
|
||||||
{
|
{
|
||||||
g2.Use(adminPermission)
|
g2.Use(adminPermission)
|
||||||
g2.GET("", adminIndex)
|
g2.GET("", adminIndex)
|
||||||
|
@ -183,6 +183,7 @@ func Start() {
|
||||||
g2.POST("/gists/:gist/delete", adminGistDelete)
|
g2.POST("/gists/:gist/delete", adminGistDelete)
|
||||||
g2.POST("/sync-fs", adminSyncReposFromFS)
|
g2.POST("/sync-fs", adminSyncReposFromFS)
|
||||||
g2.POST("/sync-db", adminSyncReposFromDB)
|
g2.POST("/sync-db", adminSyncReposFromDB)
|
||||||
|
g2.PUT("/set-setting", adminSetSetting)
|
||||||
}
|
}
|
||||||
|
|
||||||
g1.GET("/all", allGists)
|
g1.GET("/all", allGists)
|
||||||
|
@ -236,7 +237,12 @@ func dataInit(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
ctxValue := context.WithValue(ctx.Request().Context(), "data", echo.Map{})
|
ctxValue := context.WithValue(ctx.Request().Context(), "data", echo.Map{})
|
||||||
ctx.SetRequest(ctx.Request().WithContext(ctxValue))
|
ctx.SetRequest(ctx.Request().WithContext(ctxValue))
|
||||||
setData(ctx, "loadStartTime", time.Now())
|
setData(ctx, "loadStartTime", time.Now())
|
||||||
setData(ctx, "signupDisabled", config.C.DisableSignup)
|
|
||||||
|
disableSignup, err := models.GetSetting(models.SettingDisableSignup)
|
||||||
|
if err != nil {
|
||||||
|
return errorRes(500, "Cannot read setting from database", err)
|
||||||
|
}
|
||||||
|
setData(ctx, "signupDisabled", disableSignup == "1")
|
||||||
|
|
||||||
return next(ctx)
|
return next(ctx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,7 @@ func validateReservedKeywords(fl validator.FieldLevel) bool {
|
||||||
name := fl.Field().String()
|
name := fl.Field().String()
|
||||||
|
|
||||||
restrictedNames := map[string]struct{}{}
|
restrictedNames := map[string]struct{}{}
|
||||||
for _, restrictedName := range []string{"assets", "register", "login", "logout", "config", "admin", "all"} {
|
for _, restrictedName := range []string{"assets", "register", "login", "logout", "config", "admin-panel", "all"} {
|
||||||
restrictedNames[restrictedName] = struct{}{}
|
restrictedNames[restrictedName] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
22
public/admin.ts
Normal file
22
public/admin.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
registerDomSetting(document.getElementById('disable-signup') as HTMLInputElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
const setSetting = (key: string, value: string) => {
|
||||||
|
const data = new URLSearchParams();
|
||||||
|
data.append('key', key);
|
||||||
|
data.append('value', value);
|
||||||
|
data.append('_csrf', ((document.getElementsByName('_csrf')[0] as HTMLInputElement).value));
|
||||||
|
fetch('/admin-panel/set-setting', {
|
||||||
|
method: 'PUT',
|
||||||
|
credentials: 'same-origin',
|
||||||
|
body: data,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const registerDomSetting = (el: HTMLInputElement) => {
|
||||||
|
el.addEventListener('change', () => {
|
||||||
|
setSetting(el.id, el.checked ? '1' : '0');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
6
templates/base/admin_header.html
vendored
6
templates/base/admin_header.html
vendored
|
@ -9,11 +9,11 @@
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<div class="">
|
<div class="">
|
||||||
<nav class="flex space-x-4" aria-label="Tabs">
|
<nav class="flex space-x-4" aria-label="Tabs">
|
||||||
<a href="/admin" class="{{ if eq .adminHeaderPage "index" }}bg-gray-700 text-slate-300 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md
|
<a href="/admin-panel" class="{{ if eq .adminHeaderPage "index" }}bg-gray-700 text-slate-300 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md
|
||||||
{{ else }} text-gray-400 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md {{ end }}">General</a>
|
{{ else }} text-gray-400 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md {{ end }}">General</a>
|
||||||
<a href="/admin/users" class="{{ if eq .adminHeaderPage "users" }}bg-gray-700 text-slate-300 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md
|
<a href="/admin-panel/users" class="{{ if eq .adminHeaderPage "users" }}bg-gray-700 text-slate-300 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md
|
||||||
{{ else }} text-gray-400 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md {{ end }}" aria-current="page">Users</a>
|
{{ else }} text-gray-400 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md {{ end }}" aria-current="page">Users</a>
|
||||||
<a href="/admin/gists" class="{{ if eq .adminHeaderPage "gists" }}bg-gray-700 text-slate-300 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md
|
<a href="/admin-panel/gists" class="{{ if eq .adminHeaderPage "gists" }}bg-gray-700 text-slate-300 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md
|
||||||
{{ else }} text-gray-400 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md {{ end }}" aria-current="page">Gists</a>
|
{{ else }} text-gray-400 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md {{ end }}" aria-current="page">Gists</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
4
templates/base/base_header.html
vendored
4
templates/base/base_header.html
vendored
|
@ -53,7 +53,7 @@
|
||||||
<div class="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
|
<div class="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
|
||||||
{{ if .userLogged }}
|
{{ if .userLogged }}
|
||||||
{{ if .userLogged.IsAdmin }}
|
{{ if .userLogged.IsAdmin }}
|
||||||
<a href="/admin" class="hidden sm:block text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Admin</a>
|
<a href="/admin-panel" class="hidden sm:block text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Admin</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<a href="/settings" class="hidden sm:block text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Settings</a>
|
<a href="/settings" class="hidden sm:block text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Settings</a>
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
<a href="/settings" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Settings</a>
|
<a href="/settings" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Settings</a>
|
||||||
|
|
||||||
{{ if .userLogged.IsAdmin }}
|
{{ if .userLogged.IsAdmin }}
|
||||||
<a href="/admin" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Admin</a>
|
<a href="/admin-panel" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Admin</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
|
2
templates/pages/admin_gists.html
vendored
2
templates/pages/admin_gists.html
vendored
|
@ -28,7 +28,7 @@
|
||||||
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300">{{ $gist.NbLikes }}</td>
|
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300">{{ $gist.NbLikes }}</td>
|
||||||
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><span class="moment-timestamp-date">{{ $gist.CreatedAt }}</span></td>
|
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><span class="moment-timestamp-date">{{ $gist.CreatedAt }}</span></td>
|
||||||
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
|
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
|
||||||
<form action="/admin/gists/{{ $gist.ID }}/delete" method="POST" onsubmit="return confirm('Do you want to delete this gist ?')">
|
<form action="/admin-panel/gists/{{ $gist.ID }}/delete" method="POST" onsubmit="return confirm('Do you want to delete this gist ?')">
|
||||||
{{ $.csrfHtml }}
|
{{ $.csrfHtml }}
|
||||||
<button type="submit" class="text-rose-500 hover:text-rose-600">Delete</button>
|
<button type="submit" class="text-rose-500 hover:text-rose-600">Delete</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
21
templates/pages/admin_index.html
vendored
21
templates/pages/admin_index.html
vendored
|
@ -56,13 +56,13 @@
|
||||||
<span class="text-base font-bold leading-6 text-slate-300">Actions</span>
|
<span class="text-base font-bold leading-6 text-slate-300">Actions</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<form action="/admin/sync-fs" method="POST">
|
<form action="/admin-panel/sync-fs" method="POST">
|
||||||
{{ .csrfHtml }}
|
{{ .csrfHtml }}
|
||||||
<button type="submit" {{ if .syncReposFromFS }}disabled="disabled"{{ end }} class="whitespace-nowrap text-slate-300{{ if .syncReposFromFS }} text-slate-500 cursor-not-allowed {{ end }}rounded border border-gray-600 bg-gray-800 px-2.5 py-2 text-xs font-medium text-white shadow-sm hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:outline-none focus:ring-1 focus:border-primary-500 focus:ring-primary-500 leading-3">
|
<button type="submit" {{ if .syncReposFromFS }}disabled="disabled"{{ end }} class="whitespace-nowrap text-slate-300{{ if .syncReposFromFS }} text-slate-500 cursor-not-allowed {{ end }}rounded border border-gray-600 bg-gray-800 px-2.5 py-2 text-xs font-medium text-white shadow-sm hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:outline-none focus:ring-1 focus:border-primary-500 focus:ring-primary-500 leading-3">
|
||||||
Synchorize gists from filesystem
|
Synchorize gists from filesystem
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<form action="/admin/sync-db" method="POST">
|
<form action="/admin-panel/sync-db" method="POST">
|
||||||
{{ .csrfHtml }}
|
{{ .csrfHtml }}
|
||||||
<button type="submit" {{ if .syncReposFromDB }}disabled="disabled"{{ end }} class="whitespace-nowrap text-slate-300{{ if .syncReposFromDB }} text-slate-500 cursor-not-allowed {{ end }}rounded border border-gray-600 bg-gray-800 px-2.5 py-2 text-xs font-medium text-white shadow-sm hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:outline-none focus:ring-1 focus:border-primary-500 focus:ring-primary-500 leading-3">
|
<button type="submit" {{ if .syncReposFromDB }}disabled="disabled"{{ end }} class="whitespace-nowrap text-slate-300{{ if .syncReposFromDB }} text-slate-500 cursor-not-allowed {{ end }}rounded border border-gray-600 bg-gray-800 px-2.5 py-2 text-xs font-medium text-white shadow-sm hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:outline-none focus:ring-1 focus:border-primary-500 focus:ring-primary-500 leading-3">
|
||||||
Synchorize gists from database
|
Synchorize gists from database
|
||||||
|
@ -71,7 +71,24 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="sm:overflow-hidden ">
|
||||||
|
<div class="space-y-2 bg-gray-800 py-6 px-6 rounded-md border border-gray-700">
|
||||||
|
<div>
|
||||||
|
<span class="text-base font-bold leading-6 text-slate-300">Settings</span>
|
||||||
|
</div>
|
||||||
|
{{ .csrfHtml }}
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div>
|
||||||
|
<label for="disable-signup" class="text-sm text-slate-300">Disable signup</label>
|
||||||
|
<input type="checkbox" id="disable-signup" name="disable-signup" {{ if .signupDisabled }}checked="checked"{{ end }} class="ml-1 h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-600" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script type="module" src="{{ asset "admin.ts" }}"></script>
|
||||||
|
|
||||||
{{ template "admin_footer" .}}
|
{{ template "admin_footer" .}}
|
||||||
{{ template "footer" .}}
|
{{ template "footer" .}}
|
||||||
|
|
2
templates/pages/admin_users.html
vendored
2
templates/pages/admin_users.html
vendored
|
@ -20,7 +20,7 @@
|
||||||
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><a href="/{{ $user.Username }}">{{ $user.Username }}</a></td>
|
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><a href="/{{ $user.Username }}">{{ $user.Username }}</a></td>
|
||||||
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><span class="moment-timestamp-date">{{ $user.CreatedAt }}</span></td>
|
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><span class="moment-timestamp-date">{{ $user.CreatedAt }}</span></td>
|
||||||
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
|
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
|
||||||
<form action="/admin/users/{{ $user.ID }}/delete" method="POST" onsubmit="return confirm('Do you want to delete this user ?')">
|
<form action="/admin-panel/users/{{ $user.ID }}/delete" method="POST" onsubmit="return confirm('Do you want to delete this user ?')">
|
||||||
{{ $.csrfHtml }}
|
{{ $.csrfHtml }}
|
||||||
<button type="submit" class="text-rose-500 hover:text-rose-600">Delete</button>
|
<button type="submit" class="text-rose-500 hover:text-rose-600">Delete</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -9,7 +9,7 @@ export default defineConfig({
|
||||||
assetsDir: 'assets',
|
assetsDir: 'assets',
|
||||||
manifest: true,
|
manifest: true,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: ['./public/main.ts', './public/editor.ts']
|
input: ['./public/main.ts', './public/editor.ts', './public/admin.ts']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Reference in a new issue