mirror of
https://github.com/thomiceli/opengist.git
synced 2024-12-22 20:42:40 +00:00
Set gist URL and title via push options (#216)
This commit is contained in:
parent
db6d6a5eba
commit
86ad88fb09
8 changed files with 131 additions and 78 deletions
|
@ -4,6 +4,19 @@ Opengist has support for a few [Git push options](https://git-scm.com/docs/git-p
|
|||
|
||||
These options are passed to `git push` command and can be used to change the metadata of a gist.
|
||||
|
||||
## Set URL
|
||||
|
||||
```shell
|
||||
git push -o url=mygist # Will set the URL to https://opengist.example.com/user/mygist
|
||||
```
|
||||
|
||||
## Change title
|
||||
|
||||
```shell
|
||||
git push -o title=Gist123
|
||||
git push -o title="My Gist 123"
|
||||
```
|
||||
|
||||
## Change visibility
|
||||
|
||||
```shell
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/thomiceli/opengist/internal/db"
|
||||
"github.com/thomiceli/opengist/internal/git"
|
||||
"github.com/thomiceli/opengist/internal/utils"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
@ -13,7 +14,12 @@ import (
|
|||
)
|
||||
|
||||
func PostReceive(in io.Reader, out, er io.Writer) error {
|
||||
var outputSb strings.Builder
|
||||
newGist := false
|
||||
opts := pushOptions()
|
||||
gistUrl := os.Getenv("OPENGIST_REPOSITORY_URL_INTERNAL")
|
||||
validator := utils.NewValidator()
|
||||
|
||||
scanner := bufio.NewScanner(in)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
@ -29,9 +35,7 @@ func PostReceive(in io.Reader, out, er io.Writer) error {
|
|||
}
|
||||
|
||||
if oldrev == BaseHash {
|
||||
_, _ = fmt.Fprintf(out, "\nYour new repository has been created here: %s\n\n", os.Getenv("OPENGIST_REPOSITORY_URL_INTERNAL"))
|
||||
_, _ = fmt.Fprintln(out, "If you want to keep working with your gist, you could set the remote URL via:")
|
||||
_, _ = fmt.Fprintf(out, "git remote set-url origin %s\n\n", os.Getenv("OPENGIST_REPOSITORY_URL_INTERNAL"))
|
||||
newGist = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +47,22 @@ func PostReceive(in io.Reader, out, er io.Writer) error {
|
|||
|
||||
if slices.Contains([]string{"public", "unlisted", "private"}, opts["visibility"]) {
|
||||
gist.Private, _ = db.ParseVisibility(opts["visibility"])
|
||||
_, _ = fmt.Fprintf(out, "\nGist visibility set to %s\n\n", opts["visibility"])
|
||||
outputSb.WriteString(fmt.Sprintf("Gist visibility set to %s\n\n", opts["visibility"]))
|
||||
}
|
||||
|
||||
if opts["url"] != "" && validator.Var(opts["url"], "max=32,alphanumdashorempty") == nil {
|
||||
gist.URL = opts["url"]
|
||||
lastIndex := strings.LastIndex(gistUrl, "/")
|
||||
gistUrl = gistUrl[:lastIndex+1] + gist.URL
|
||||
if !newGist {
|
||||
outputSb.WriteString(fmt.Sprintf("Gist URL set to %s. Set the Git remote URL via:\n", gistUrl))
|
||||
outputSb.WriteString(fmt.Sprintf("git remote set-url origin %s\n\n", gistUrl))
|
||||
}
|
||||
}
|
||||
|
||||
if opts["title"] != "" && validator.Var(opts["title"], "max=250") == nil {
|
||||
gist.Title = opts["title"]
|
||||
outputSb.WriteString(fmt.Sprintf("Gist title set to \"%s\"\n\n", opts["title"]))
|
||||
}
|
||||
|
||||
if hasNoCommits, err := git.HasNoCommits(gist.User.Username, gist.Uuid); err != nil {
|
||||
|
@ -65,6 +84,17 @@ func PostReceive(in io.Reader, out, er io.Writer) error {
|
|||
|
||||
gist.AddInIndex()
|
||||
|
||||
if newGist {
|
||||
outputSb.WriteString(fmt.Sprintf("Your new gist has been created here: %s\n", gistUrl))
|
||||
outputSb.WriteString("If you want to keep working with your gist, you could set the Git remote URL via:\n")
|
||||
outputSb.WriteString(fmt.Sprintf("git remote set-url origin %s\n\n", gistUrl))
|
||||
}
|
||||
|
||||
outputStr := outputSb.String()
|
||||
if outputStr != "" {
|
||||
_, _ = fmt.Fprint(out, "\n"+outputStr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
74
internal/utils/validator.go
Normal file
74
internal/utils/validator.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"github.com/go-playground/validator/v10"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OpengistValidator struct {
|
||||
v *validator.Validate
|
||||
}
|
||||
|
||||
func NewValidator() *OpengistValidator {
|
||||
v := validator.New()
|
||||
_ = v.RegisterValidation("notreserved", validateReservedKeywords)
|
||||
_ = v.RegisterValidation("alphanumdash", validateAlphaNumDash)
|
||||
_ = v.RegisterValidation("alphanumdashorempty", validateAlphaNumDashOrEmpty)
|
||||
return &OpengistValidator{v}
|
||||
}
|
||||
|
||||
func (cv *OpengistValidator) Validate(i interface{}) error {
|
||||
return cv.v.Struct(i)
|
||||
}
|
||||
|
||||
func (cv *OpengistValidator) Var(field interface{}, tag string) error {
|
||||
return cv.v.Var(field, tag)
|
||||
}
|
||||
|
||||
func ValidationMessages(err *error) string {
|
||||
errs := (*err).(validator.ValidationErrors)
|
||||
messages := make([]string, len(errs))
|
||||
for i, e := range errs {
|
||||
switch e.Tag() {
|
||||
case "max":
|
||||
messages[i] = e.Field() + " is too long"
|
||||
case "required":
|
||||
messages[i] = e.Field() + " should not be empty"
|
||||
case "excludes":
|
||||
messages[i] = e.Field() + " should not include a sub directory"
|
||||
case "alphanum":
|
||||
messages[i] = e.Field() + " should only contain alphanumeric characters"
|
||||
case "alphanumdash":
|
||||
case "alphanumdashorempty":
|
||||
messages[i] = e.Field() + " should only contain alphanumeric characters and dashes"
|
||||
case "min":
|
||||
messages[i] = "Not enough " + e.Field()
|
||||
case "notreserved":
|
||||
messages[i] = "Invalid " + e.Field()
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(messages, " ; ")
|
||||
}
|
||||
|
||||
func validateReservedKeywords(fl validator.FieldLevel) bool {
|
||||
name := fl.Field().String()
|
||||
|
||||
restrictedNames := map[string]struct{}{}
|
||||
for _, restrictedName := range []string{"assets", "register", "login", "logout", "settings", "admin-panel", "all", "search", "init", "healthcheck"} {
|
||||
restrictedNames[restrictedName] = struct{}{}
|
||||
}
|
||||
|
||||
// if the name is not in the restricted names, it is valid
|
||||
_, ok := restrictedNames[name]
|
||||
return !ok
|
||||
}
|
||||
|
||||
func validateAlphaNumDash(fl validator.FieldLevel) bool {
|
||||
return regexp.MustCompile(`^[a-zA-Z0-9-]+$`).MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
func validateAlphaNumDashOrEmpty(fl validator.FieldLevel) bool {
|
||||
return regexp.MustCompile(`^$|^[a-zA-Z0-9-]+$`).MatchString(fl.Field().String())
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/thomiceli/opengist/internal/utils"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -63,7 +64,7 @@ func processRegister(ctx echo.Context) error {
|
|||
}
|
||||
|
||||
if err := ctx.Validate(dto); err != nil {
|
||||
addFlash(ctx, validationMessages(&err), "error")
|
||||
addFlash(ctx, utils.ValidationMessages(&err), "error")
|
||||
return html(ctx, "auth_form.html")
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/thomiceli/opengist/internal/git"
|
||||
"github.com/thomiceli/opengist/internal/index"
|
||||
"github.com/thomiceli/opengist/internal/render"
|
||||
"github.com/thomiceli/opengist/internal/utils"
|
||||
"html/template"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
|
@ -539,7 +540,7 @@ func processCreate(ctx echo.Context) error {
|
|||
|
||||
err = ctx.Validate(dto)
|
||||
if err != nil {
|
||||
addFlash(ctx, validationMessages(&err), "error")
|
||||
addFlash(ctx, utils.ValidationMessages(&err), "error")
|
||||
if isCreate {
|
||||
return html(ctx, "create.html")
|
||||
} else {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"github.com/thomiceli/opengist/internal/index"
|
||||
"github.com/thomiceli/opengist/internal/utils"
|
||||
htmlpkg "html"
|
||||
"html/template"
|
||||
"io"
|
||||
|
@ -205,7 +206,7 @@ func NewServer(isDev bool) *Server {
|
|||
|
||||
e.Use(sessionInit)
|
||||
|
||||
e.Validator = NewValidator()
|
||||
e.Validator = utils.NewValidator()
|
||||
|
||||
if !dev {
|
||||
parseManifestEntries()
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/thomiceli/opengist/internal/config"
|
||||
"github.com/thomiceli/opengist/internal/git"
|
||||
"github.com/thomiceli/opengist/internal/utils"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
@ -73,7 +74,7 @@ func sshKeysProcess(ctx echo.Context) error {
|
|||
}
|
||||
|
||||
if err := ctx.Validate(dto); err != nil {
|
||||
addFlash(ctx, validationMessages(&err), "error")
|
||||
addFlash(ctx, utils.ValidationMessages(&err), "error")
|
||||
return redirect(ctx, "/settings")
|
||||
}
|
||||
key := dto.ToSSHKey()
|
||||
|
@ -126,7 +127,7 @@ func passwordProcess(ctx echo.Context) error {
|
|||
dto.Username = user.Username
|
||||
|
||||
if err := ctx.Validate(dto); err != nil {
|
||||
addFlash(ctx, validationMessages(&err), "error")
|
||||
addFlash(ctx, utils.ValidationMessages(&err), "error")
|
||||
return html(ctx, "settings.html")
|
||||
}
|
||||
|
||||
|
@ -154,7 +155,7 @@ func usernameProcess(ctx echo.Context) error {
|
|||
dto.Password = user.Password
|
||||
|
||||
if err := ctx.Validate(dto); err != nil {
|
||||
addFlash(ctx, validationMessages(&err), "error")
|
||||
addFlash(ctx, utils.ValidationMessages(&err), "error")
|
||||
return redirect(ctx, "/settings")
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/thomiceli/opengist/internal/config"
|
||||
|
@ -16,7 +15,6 @@ import (
|
|||
"golang.org/x/crypto/argon2"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
@ -129,72 +127,6 @@ func loadSettings(ctx echo.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type OpengistValidator struct {
|
||||
v *validator.Validate
|
||||
}
|
||||
|
||||
func NewValidator() *OpengistValidator {
|
||||
v := validator.New()
|
||||
_ = v.RegisterValidation("notreserved", validateReservedKeywords)
|
||||
_ = v.RegisterValidation("alphanumdash", validateAlphaNumDash)
|
||||
_ = v.RegisterValidation("alphanumdashorempty", validateAlphaNumDashOrEmpty)
|
||||
return &OpengistValidator{v}
|
||||
}
|
||||
|
||||
func (cv *OpengistValidator) Validate(i interface{}) error {
|
||||
if err := cv.v.Struct(i); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validationMessages(err *error) string {
|
||||
errs := (*err).(validator.ValidationErrors)
|
||||
messages := make([]string, len(errs))
|
||||
for i, e := range errs {
|
||||
switch e.Tag() {
|
||||
case "max":
|
||||
messages[i] = e.Field() + " is too long"
|
||||
case "required":
|
||||
messages[i] = e.Field() + " should not be empty"
|
||||
case "excludes":
|
||||
messages[i] = e.Field() + " should not include a sub directory"
|
||||
case "alphanum":
|
||||
messages[i] = e.Field() + " should only contain alphanumeric characters"
|
||||
case "alphanumdash":
|
||||
case "alphanumdashorempty":
|
||||
messages[i] = e.Field() + " should only contain alphanumeric characters and dashes"
|
||||
case "min":
|
||||
messages[i] = "Not enough " + e.Field()
|
||||
case "notreserved":
|
||||
messages[i] = "Invalid " + e.Field()
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(messages, " ; ")
|
||||
}
|
||||
|
||||
func validateReservedKeywords(fl validator.FieldLevel) bool {
|
||||
name := fl.Field().String()
|
||||
|
||||
restrictedNames := map[string]struct{}{}
|
||||
for _, restrictedName := range []string{"assets", "register", "login", "logout", "settings", "admin-panel", "all", "search", "init", "healthcheck"} {
|
||||
restrictedNames[restrictedName] = struct{}{}
|
||||
}
|
||||
|
||||
// if the name is not in the restricted names, it is valid
|
||||
_, ok := restrictedNames[name]
|
||||
return !ok
|
||||
}
|
||||
|
||||
func validateAlphaNumDash(fl validator.FieldLevel) bool {
|
||||
return regexp.MustCompile(`^[a-zA-Z0-9-]+$`).MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
func validateAlphaNumDashOrEmpty(fl validator.FieldLevel) bool {
|
||||
return regexp.MustCompile(`^$|^[a-zA-Z0-9-]+$`).MatchString(fl.Field().String())
|
||||
}
|
||||
|
||||
func getPage(ctx echo.Context) int {
|
||||
page := ctx.QueryParam("page")
|
||||
if page == "" {
|
||||
|
|
Loading…
Reference in a new issue