mirror of
https://github.com/thomiceli/opengist.git
synced 2024-12-23 13:02:39 +00:00
Enhanced model structs with DTOs
This commit is contained in:
parent
42176c42c5
commit
167abd4ae5
10 changed files with 212 additions and 139 deletions
|
@ -8,13 +8,13 @@ import (
|
||||||
type Gist struct {
|
type Gist struct {
|
||||||
ID uint `gorm:"primaryKey"`
|
ID uint `gorm:"primaryKey"`
|
||||||
Uuid string
|
Uuid string
|
||||||
Title string `validate:"max=50" form:"title"`
|
Title string
|
||||||
Preview string
|
Preview string
|
||||||
PreviewFilename string
|
PreviewFilename string
|
||||||
Description string `validate:"max=150" form:"description"`
|
Description string
|
||||||
Private bool `form:"private"`
|
Private bool
|
||||||
UserID uint
|
UserID uint
|
||||||
User User `validate:"-"`
|
User User
|
||||||
NbFiles int
|
NbFiles int
|
||||||
NbLikes int
|
NbLikes int
|
||||||
NbForks int
|
NbForks int
|
||||||
|
@ -25,7 +25,7 @@ type Gist struct {
|
||||||
Forked *Gist `gorm:"foreignKey:ForkedID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL"`
|
Forked *Gist `gorm:"foreignKey:ForkedID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL"`
|
||||||
ForkedID uint
|
ForkedID uint
|
||||||
|
|
||||||
Files []File `gorm:"-" validate:"min=1,dive"`
|
Files []File `gorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type File struct {
|
type File struct {
|
||||||
|
@ -42,11 +42,11 @@ type Commit struct {
|
||||||
Files []File
|
Files []File
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gist) BeforeDelete(tx *gorm.DB) error {
|
func (gist *Gist) BeforeDelete(tx *gorm.DB) error {
|
||||||
// Decrement fork counter if the gist was forked
|
// Decrement fork counter if the gist was forked
|
||||||
err := tx.Model(&Gist{}).
|
err := tx.Model(&Gist{}).
|
||||||
Omit("updated_at").
|
Omit("updated_at").
|
||||||
Where("id = ?", g.ForkedID).
|
Where("id = ?", gist.ForkedID).
|
||||||
UpdateColumn("nb_forks", gorm.Expr("nb_forks - 1")).Error
|
UpdateColumn("nb_forks", gorm.Expr("nb_forks - 1")).Error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -83,14 +83,14 @@ func GetAllGistsForCurrentUser(currentUserId uint, offset int, sort string, orde
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllGists(offset int) ([]*Gist, error) {
|
func GetAllGists(offset int) ([]*Gist, error) {
|
||||||
var all []*Gist
|
var gists []*Gist
|
||||||
err := db.Preload("User").
|
err := db.Preload("User").
|
||||||
Limit(11).
|
Limit(11).
|
||||||
Offset(offset * 10).
|
Offset(offset * 10).
|
||||||
Order("id asc").
|
Order("id asc").
|
||||||
Find(&all).Error
|
Find(&gists).Error
|
||||||
|
|
||||||
return all, err
|
return gists, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllGistsFromUser(fromUser string, currentUserId uint, offset int, sort string, order string) ([]*Gist, error) {
|
func GetAllGistsFromUser(fromUser string, currentUserId uint, offset int, sort string, order string) ([]*Gist, error) {
|
||||||
|
@ -106,30 +106,30 @@ func GetAllGistsFromUser(fromUser string, currentUserId uint, offset int, sort s
|
||||||
return gists, err
|
return gists, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateGist(gist *Gist) error {
|
func (gist *Gist) Create() error {
|
||||||
// avoids foreign key constraint error because the default value in the struct is 0
|
// avoids foreign key constraint error because the default value in the struct is 0
|
||||||
return db.Omit("forked_id").Create(&gist).Error
|
return db.Omit("forked_id").Create(&gist).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateForkedGist(gist *Gist) error {
|
func (gist *Gist) CreateForked() error {
|
||||||
return db.Create(&gist).Error
|
return db.Create(&gist).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateGist(gist *Gist) error {
|
func (gist *Gist) Update() error {
|
||||||
return db.Omit("forked_id").Save(&gist).Error
|
return db.Omit("forked_id").Save(&gist).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteGist(gist *Gist) error {
|
func (gist *Gist) Delete() error {
|
||||||
return db.Delete(&gist).Error
|
return db.Delete(&gist).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func GistLastActiveNow(gistID uint) error {
|
func (gist *Gist) SetLastActiveNow() error {
|
||||||
return db.Model(&Gist{}).
|
return db.Model(&Gist{}).
|
||||||
Where("id = ?", gistID).
|
Where("id = ?", gist.ID).
|
||||||
Update("updated_at", time.Now().Unix()).Error
|
Update("updated_at", time.Now().Unix()).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppendUserLike(gist *Gist, user *User) error {
|
func (gist *Gist) AppendUserLike(user *User) error {
|
||||||
err := db.Model(&gist).Omit("updated_at").Update("nb_likes", gist.NbLikes+1).Error
|
err := db.Model(&gist).Omit("updated_at").Update("nb_likes", gist.NbLikes+1).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -138,7 +138,7 @@ func AppendUserLike(gist *Gist, user *User) error {
|
||||||
return db.Model(&gist).Omit("updated_at").Association("Likes").Append(user)
|
return db.Model(&gist).Omit("updated_at").Association("Likes").Append(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveUserLike(gist *Gist, user *User) error {
|
func (gist *Gist) RemoveUserLike(user *User) error {
|
||||||
err := db.Model(&gist).Omit("updated_at").Update("nb_likes", gist.NbLikes-1).Error
|
err := db.Model(&gist).Omit("updated_at").Update("nb_likes", gist.NbLikes-1).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -147,11 +147,11 @@ func RemoveUserLike(gist *Gist, user *User) error {
|
||||||
return db.Model(&gist).Omit("updated_at").Association("Likes").Delete(user)
|
return db.Model(&gist).Omit("updated_at").Association("Likes").Delete(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IncrementGistForkCount(gist *Gist) error {
|
func (gist *Gist) IncrementForkCount() error {
|
||||||
return db.Model(&gist).Omit("updated_at").Update("nb_forks", gist.NbForks+1).Error
|
return db.Model(&gist).Omit("updated_at").Update("nb_forks", gist.NbForks+1).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetForkedGist(gist *Gist, user *User) (*Gist, error) {
|
func (gist *Gist) GetForkParent(user *User) (*Gist, error) {
|
||||||
fork := new(Gist)
|
fork := new(Gist)
|
||||||
err := db.Preload("User").
|
err := db.Preload("User").
|
||||||
Where("forked_id = ? and user_id = ?", gist.ID, user.ID).
|
Where("forked_id = ? and user_id = ?", gist.ID, user.ID).
|
||||||
|
@ -159,7 +159,7 @@ func GetForkedGist(gist *Gist, user *User) (*Gist, error) {
|
||||||
return fork, err
|
return fork, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUsersLikesForGist(gist *Gist, offset int) ([]*User, error) {
|
func (gist *Gist) GetUsersLikes(offset int) ([]*User, error) {
|
||||||
var users []*User
|
var users []*User
|
||||||
err := db.Model(&gist).
|
err := db.Model(&gist).
|
||||||
Where("gist_id = ?", gist.ID).
|
Where("gist_id = ?", gist.ID).
|
||||||
|
@ -169,7 +169,7 @@ func GetUsersLikesForGist(gist *Gist, offset int) ([]*User, error) {
|
||||||
return users, err
|
return users, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUsersForksForGist(gist *Gist, currentUserId uint, offset int) ([]*Gist, error) {
|
func (gist *Gist) GetForks(currentUserId uint, offset int) ([]*Gist, error) {
|
||||||
var gists []*Gist
|
var gists []*Gist
|
||||||
err := db.Model(&gist).Preload("User").
|
err := db.Model(&gist).Preload("User").
|
||||||
Where("forked_id = ?", gist.ID).
|
Where("forked_id = ?", gist.ID).
|
||||||
|
@ -182,6 +182,32 @@ func GetUsersForksForGist(gist *Gist, currentUserId uint, offset int) ([]*Gist,
|
||||||
return gists, err
|
return gists, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func UserCanWrite(user *User, gist *Gist) bool {
|
func (gist *Gist) CanWrite(user *User) bool {
|
||||||
return !(user == nil) && (gist.UserID == user.ID)
|
return !(user == nil) && (gist.UserID == user.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- DTO -- //
|
||||||
|
|
||||||
|
type GistDTO struct {
|
||||||
|
Title string `validate:"max=50" form:"title"`
|
||||||
|
Description string `validate:"max=150" form:"description"`
|
||||||
|
Private bool `form:"private"`
|
||||||
|
Files []File `validate:"min=1,dive"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dto *GistDTO) ToGist() *Gist {
|
||||||
|
return &Gist{
|
||||||
|
Title: dto.Title,
|
||||||
|
Description: dto.Description,
|
||||||
|
Private: dto.Private,
|
||||||
|
Files: dto.Files,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dto *GistDTO) ToExistingGist(gist *Gist) *Gist {
|
||||||
|
gist.Title = dto.Title
|
||||||
|
gist.Description = dto.Description
|
||||||
|
gist.Private = dto.Private
|
||||||
|
gist.Files = dto.Files
|
||||||
|
return gist
|
||||||
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ package models
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type SSHKey struct {
|
type SSHKey struct {
|
||||||
ID uint `gorm:"primaryKey"`
|
ID uint `gorm:"primaryKey"`
|
||||||
Title string `form:"title" validate:"required,max=50"`
|
Title string
|
||||||
Content string `form:"content" validate:"required"`
|
Content string
|
||||||
SHA string
|
SHA string
|
||||||
CreatedAt int64
|
CreatedAt int64
|
||||||
LastUsedAt int64
|
LastUsedAt int64
|
||||||
|
@ -41,11 +41,11 @@ func GetSSHKeyByContent(sshKeyContent string) (*SSHKey, error) {
|
||||||
return sshKey, err
|
return sshKey, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddSSHKey(sshKey *SSHKey) error {
|
func (sshKey *SSHKey) Create() error {
|
||||||
return db.Create(&sshKey).Error
|
return db.Create(&sshKey).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveSSHKey(sshKey *SSHKey) error {
|
func (sshKey *SSHKey) Delete() error {
|
||||||
return db.Delete(&sshKey).Error
|
return db.Delete(&sshKey).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,3 +54,17 @@ func SSHKeyLastUsedNow(sshKeyID uint) error {
|
||||||
Where("id = ?", sshKeyID).
|
Where("id = ?", sshKeyID).
|
||||||
Update("last_used_at", time.Now().Unix()).Error
|
Update("last_used_at", time.Now().Unix()).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- DTO -- //
|
||||||
|
|
||||||
|
type SSHKeyDTO struct {
|
||||||
|
Title string `form:"title" validate:"required,max=50"`
|
||||||
|
Content string `form:"content" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dto *SSHKeyDTO) ToSSHKey() *SSHKey {
|
||||||
|
return &SSHKey{
|
||||||
|
Title: dto.Title,
|
||||||
|
Content: dto.Content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,13 +2,12 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID uint `gorm:"primaryKey"`
|
ID uint `gorm:"primaryKey"`
|
||||||
Username string `form:"username" gorm:"uniqueIndex" validate:"required,max=24,alphanum,notreserved"`
|
Username string `gorm:"uniqueIndex"`
|
||||||
Password string `form:"password" validate:"required"`
|
Password string
|
||||||
IsAdmin bool
|
IsAdmin bool
|
||||||
CreatedAt int64
|
CreatedAt int64
|
||||||
|
|
||||||
|
@ -17,7 +16,7 @@ type User struct {
|
||||||
Liked []Gist `gorm:"many2many:likes;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
Liked []Gist `gorm:"many2many:likes;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) BeforeDelete(tx *gorm.DB) error {
|
func (user *User) BeforeDelete(tx *gorm.DB) error {
|
||||||
// Decrement likes counter for all gists liked by this user
|
// Decrement likes counter for all gists liked by this user
|
||||||
// The likes will be automatically deleted by the foreign key constraint
|
// The likes will be automatically deleted by the foreign key constraint
|
||||||
err := tx.Model(&Gist{}).
|
err := tx.Model(&Gist{}).
|
||||||
|
@ -25,7 +24,7 @@ func (u *User) BeforeDelete(tx *gorm.DB) error {
|
||||||
Where("id IN (?)", tx.
|
Where("id IN (?)", tx.
|
||||||
Select("gist_id").
|
Select("gist_id").
|
||||||
Table("likes").
|
Table("likes").
|
||||||
Where("user_id = ?", u.ID),
|
Where("user_id = ?", user.ID),
|
||||||
).
|
).
|
||||||
UpdateColumn("nb_likes", gorm.Expr("nb_likes - 1")).
|
UpdateColumn("nb_likes", gorm.Expr("nb_likes - 1")).
|
||||||
Error
|
Error
|
||||||
|
@ -39,57 +38,43 @@ func (u *User) BeforeDelete(tx *gorm.DB) error {
|
||||||
Where("id IN (?)", tx.
|
Where("id IN (?)", tx.
|
||||||
Select("forked_id").
|
Select("forked_id").
|
||||||
Table("gists").
|
Table("gists").
|
||||||
Where("user_id = ?", u.ID),
|
Where("user_id = ?", user.ID),
|
||||||
).
|
).
|
||||||
UpdateColumn("nb_forks", gorm.Expr("nb_forks - 1")).
|
UpdateColumn("nb_forks", gorm.Expr("nb_forks - 1")).
|
||||||
Error
|
Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func DoesUserExists(userName string, count *int64) error {
|
func UserExists(username string) (bool, error) {
|
||||||
return db.Table("users").
|
var count int64
|
||||||
Where("username like ?", userName).
|
err := db.Model(&User{}).Where("username like ?", username).Count(&count).Error
|
||||||
Count(count).Error
|
return count > 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllUsers(offset int) ([]*User, error) {
|
func GetAllUsers(offset int) ([]*User, error) {
|
||||||
var all []*User
|
var users []*User
|
||||||
err := db.
|
err := db.
|
||||||
Limit(11).
|
Limit(11).
|
||||||
Offset(offset * 10).
|
Offset(offset * 10).
|
||||||
Order("id asc").
|
Order("id asc").
|
||||||
Find(&all).Error
|
Find(&users).Error
|
||||||
|
|
||||||
return all, err
|
return users, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetLoginUser(user *User) error {
|
func GetUserByUsername(username string) (*User, error) {
|
||||||
return db.
|
user := new(User)
|
||||||
Where("username like ?", user.Username).
|
err := db.
|
||||||
|
Where("username like ?", username).
|
||||||
First(&user).Error
|
First(&user).Error
|
||||||
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetLoginUserById(user *User) error {
|
func GetUserById(userId uint) (*User, error) {
|
||||||
return db.
|
user := new(User)
|
||||||
Where("id = ?", user.ID).
|
err := db.
|
||||||
|
Where("id = ?", userId).
|
||||||
First(&user).Error
|
First(&user).Error
|
||||||
}
|
return user, err
|
||||||
|
|
||||||
func CreateUser(user *User) error {
|
|
||||||
return db.Create(&user).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteUser(userid string) error {
|
|
||||||
// trigger hook with a user ID
|
|
||||||
intId, err := strconv.ParseUint(userid, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var user = &User{ID: uint(intId)}
|
|
||||||
return db.Where("id = ?", userid).Delete(&user).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetAdminUser(user *User) error {
|
|
||||||
return db.Model(&user).Update("is_admin", true).Error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserBySSHKeyID(sshKeyId uint) (*User, error) {
|
func GetUserBySSHKeyID(sshKeyId uint) (*User, error) {
|
||||||
|
@ -103,7 +88,19 @@ func GetUserBySSHKeyID(sshKeyId uint) (*User, error) {
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func UserHasLikedGist(user *User, gist *Gist) (bool, error) {
|
func (user *User) Create() error {
|
||||||
|
return db.Create(&user).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) Delete() error {
|
||||||
|
return db.Delete(&user).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) SetAdmin() error {
|
||||||
|
return db.Model(&user).Update("is_admin", true).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) HasLiked(gist *Gist) (bool, error) {
|
||||||
association := db.Model(&gist).Where("user_id = ?", user.ID).Association("Likes")
|
association := db.Model(&gist).Where("user_id = ?", user.ID).Association("Likes")
|
||||||
if association.Error != nil {
|
if association.Error != nil {
|
||||||
return false, association.Error
|
return false, association.Error
|
||||||
|
@ -114,3 +111,17 @@ func UserHasLikedGist(user *User, gist *Gist) (bool, error) {
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- DTO -- //
|
||||||
|
|
||||||
|
type UserDTO struct {
|
||||||
|
Username string `form:"username" validate:"required,max=24,alphanum,notreserved"`
|
||||||
|
Password string `form:"password" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dto *UserDTO) ToUser() *User {
|
||||||
|
return &User{
|
||||||
|
Username: dto.Username,
|
||||||
|
Password: dto.Password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ func runGitCommand(ch ssh.Channel, gitCmd string, keyID uint) error {
|
||||||
|
|
||||||
// updatedAt is updated only if serviceType is receive-pack
|
// updatedAt is updated only if serviceType is receive-pack
|
||||||
if verb == "receive-pack" {
|
if verb == "receive-pack" {
|
||||||
_ = models.GistLastActiveNow(gist.ID)
|
_ = gist.SetLastActiveNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"opengist/internal/git"
|
"opengist/internal/git"
|
||||||
"opengist/internal/models"
|
"opengist/internal/models"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func adminIndex(ctx echo.Context) error {
|
func adminIndex(ctx echo.Context) error {
|
||||||
|
@ -78,7 +79,13 @@ func adminGists(ctx echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func adminUserDelete(ctx echo.Context) error {
|
func adminUserDelete(ctx echo.Context) error {
|
||||||
if err := models.DeleteUser(ctx.Param("user")); err != nil {
|
userId, _ := strconv.ParseUint(ctx.Param("user"), 10, 64)
|
||||||
|
user, err := models.GetUserById(uint(userId))
|
||||||
|
if err != nil {
|
||||||
|
return errorRes(500, "Cannot retrieve user", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := user.Delete(); err != nil {
|
||||||
return errorRes(500, "Cannot delete this user", err)
|
return errorRes(500, "Cannot delete this user", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +103,7 @@ func adminGistDelete(ctx echo.Context) error {
|
||||||
return errorRes(500, "Cannot delete the repository", err)
|
return errorRes(500, "Cannot delete the repository", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = models.DeleteGist(gist); err != nil {
|
if err = gist.Delete(); err != nil {
|
||||||
return errorRes(500, "Cannot delete this gist", err)
|
return errorRes(500, "Cannot delete this gist", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,35 +22,35 @@ func processRegister(ctx echo.Context) error {
|
||||||
|
|
||||||
sess := getSession(ctx)
|
sess := getSession(ctx)
|
||||||
|
|
||||||
var user = new(models.User)
|
var dto = new(models.UserDTO)
|
||||||
if err := ctx.Bind(user); err != nil {
|
if err := ctx.Bind(dto); err != nil {
|
||||||
return errorRes(400, "Cannot bind data", err)
|
return errorRes(400, "Cannot bind data", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ctx.Validate(user); err != nil {
|
if err := ctx.Validate(dto); err != nil {
|
||||||
addFlash(ctx, validationMessages(&err), "error")
|
addFlash(ctx, validationMessages(&err), "error")
|
||||||
return html(ctx, "auth_form.html")
|
return html(ctx, "auth_form.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if exists, err := models.UserExists(dto.Username); err != nil || exists {
|
||||||
|
addFlash(ctx, "Username already exists", "error")
|
||||||
|
return html(ctx, "auth_form.html")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := dto.ToUser()
|
||||||
|
|
||||||
password, err := argon2id.hash(user.Password)
|
password, err := argon2id.hash(user.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorRes(500, "Cannot hash password", err)
|
return errorRes(500, "Cannot hash password", err)
|
||||||
}
|
}
|
||||||
user.Password = password
|
user.Password = password
|
||||||
|
|
||||||
var count int64
|
if err = user.Create(); err != nil {
|
||||||
if err = models.DoesUserExists(user.Username, &count); err != nil || count >= 1 {
|
|
||||||
addFlash(ctx, "Username already exists", "error")
|
|
||||||
return html(ctx, "auth_form.html")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = models.CreateUser(user); err != nil {
|
|
||||||
return errorRes(500, "Cannot create user", err)
|
return errorRes(500, "Cannot create user", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.ID == 1 {
|
if user.ID == 1 {
|
||||||
user.IsAdmin = true
|
if err = user.SetAdmin(); err != nil {
|
||||||
if err = models.SetAdminUser(user); err != nil {
|
|
||||||
return errorRes(500, "Cannot set user admin", err)
|
return errorRes(500, "Cannot set user admin", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,15 +68,18 @@ func login(ctx echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func processLogin(ctx echo.Context) error {
|
func processLogin(ctx echo.Context) error {
|
||||||
|
var err error
|
||||||
sess := getSession(ctx)
|
sess := getSession(ctx)
|
||||||
|
|
||||||
user := &models.User{}
|
dto := &models.UserDTO{}
|
||||||
if err := ctx.Bind(user); err != nil {
|
if err = ctx.Bind(dto); err != nil {
|
||||||
return errorRes(400, "Cannot bind data", err)
|
return errorRes(400, "Cannot bind data", err)
|
||||||
}
|
}
|
||||||
password := user.Password
|
password := dto.Password
|
||||||
|
|
||||||
if err := models.GetLoginUser(user); err != nil {
|
var user *models.User
|
||||||
|
|
||||||
|
if user, err = models.GetUserByUsername(dto.Username); err != nil {
|
||||||
addFlash(ctx, "Invalid credentials", "error")
|
addFlash(ctx, "Invalid credentials", "error")
|
||||||
return redirect(ctx, "/login")
|
return redirect(ctx, "/login")
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
@ -59,7 +60,7 @@ func gistInit(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
setData(ctx, "nbCommits", nbCommits)
|
setData(ctx, "nbCommits", nbCommits)
|
||||||
|
|
||||||
if currUser := getUserLogged(ctx); currUser != nil {
|
if currUser := getUserLogged(ctx); currUser != nil {
|
||||||
hasLiked, err := models.UserHasLikedGist(currUser, gist)
|
hasLiked, err := currUser.HasLiked(gist)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorRes(500, "Cannot get user like status", err)
|
return errorRes(500, "Cannot get user like status", err)
|
||||||
}
|
}
|
||||||
|
@ -108,12 +109,12 @@ func allGists(ctx echo.Context) error {
|
||||||
setData(ctx, "htmlTitle", "All gists from "+fromUser)
|
setData(ctx, "htmlTitle", "All gists from "+fromUser)
|
||||||
setData(ctx, "fromUser", fromUser)
|
setData(ctx, "fromUser", fromUser)
|
||||||
|
|
||||||
var count int64
|
var exists bool
|
||||||
if err = models.DoesUserExists(fromUser, &count); err != nil {
|
if exists, err = models.UserExists(fromUser); err != nil {
|
||||||
return errorRes(500, "Error fetching user", err)
|
return errorRes(500, "Error fetching user", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if count == 0 {
|
if !exists {
|
||||||
return notFound("User not found")
|
return notFound("User not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ func allGists(ctx echo.Context) error {
|
||||||
return html(ctx, "all.html")
|
return html(ctx, "all.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
func gist(ctx echo.Context) error {
|
func gistIndex(ctx echo.Context) error {
|
||||||
gist := getData(ctx, "gist").(*models.Gist)
|
gist := getData(ctx, "gist").(*models.Gist)
|
||||||
userName := gist.User.Username
|
userName := gist.User.Username
|
||||||
gistName := gist.Uuid
|
gistName := gist.Uuid
|
||||||
|
@ -244,21 +245,22 @@ func processCreate(ctx echo.Context) error {
|
||||||
return errorRes(400, "Bad request", err)
|
return errorRes(400, "Bad request", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dto := new(models.GistDTO)
|
||||||
var gist *models.Gist
|
var gist *models.Gist
|
||||||
|
|
||||||
if isCreate {
|
if isCreate {
|
||||||
gist = new(models.Gist)
|
|
||||||
setData(ctx, "htmlTitle", "Create a new gist")
|
setData(ctx, "htmlTitle", "Create a new gist")
|
||||||
} else {
|
} else {
|
||||||
gist = getData(ctx, "gist").(*models.Gist)
|
gist = getData(ctx, "gist").(*models.Gist)
|
||||||
setData(ctx, "htmlTitle", "Edit "+gist.Title)
|
setData(ctx, "htmlTitle", "Edit "+gist.Title)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ctx.Bind(gist); err != nil {
|
if err := ctx.Bind(dto); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
return errorRes(400, "Cannot bind data", err)
|
return errorRes(400, "Cannot bind data", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gist.Files = make([]models.File, 0)
|
dto.Files = make([]models.File, 0)
|
||||||
for i := 0; i < len(ctx.Request().PostForm["content"]); i++ {
|
for i := 0; i < len(ctx.Request().PostForm["content"]); i++ {
|
||||||
name := ctx.Request().PostForm["name"][i]
|
name := ctx.Request().PostForm["name"][i]
|
||||||
content := ctx.Request().PostForm["content"][i]
|
content := ctx.Request().PostForm["content"][i]
|
||||||
|
@ -272,33 +274,13 @@ func processCreate(ctx echo.Context) error {
|
||||||
return errorRes(400, "Invalid character unescaped", err)
|
return errorRes(400, "Invalid character unescaped", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gist.Files = append(gist.Files, models.File{
|
dto.Files = append(dto.Files, models.File{
|
||||||
Filename: name,
|
Filename: name,
|
||||||
Content: escapedValue,
|
Content: escapedValue,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
user := getUserLogged(ctx)
|
|
||||||
gist.NbFiles = len(gist.Files)
|
|
||||||
|
|
||||||
if isCreate {
|
err = ctx.Validate(dto)
|
||||||
uuidGist, err := uuid.NewRandom()
|
|
||||||
if err != nil {
|
|
||||||
return errorRes(500, "Error creating an UUID", err)
|
|
||||||
}
|
|
||||||
gist.Uuid = strings.Replace(uuidGist.String(), "-", "", -1)
|
|
||||||
|
|
||||||
gist.UserID = user.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
if gist.Title == "" {
|
|
||||||
if ctx.Request().PostForm["name"][0] == "" {
|
|
||||||
gist.Title = "gist:" + gist.Uuid
|
|
||||||
} else {
|
|
||||||
gist.Title = ctx.Request().PostForm["name"][0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ctx.Validate(gist)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
addFlash(ctx, validationMessages(&err), "error")
|
addFlash(ctx, validationMessages(&err), "error")
|
||||||
if isCreate {
|
if isCreate {
|
||||||
|
@ -321,6 +303,33 @@ func processCreate(ctx echo.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isCreate {
|
||||||
|
gist = dto.ToGist()
|
||||||
|
} else {
|
||||||
|
gist = dto.ToExistingGist(gist)
|
||||||
|
}
|
||||||
|
|
||||||
|
user := getUserLogged(ctx)
|
||||||
|
gist.NbFiles = len(gist.Files)
|
||||||
|
|
||||||
|
if isCreate {
|
||||||
|
uuidGist, err := uuid.NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
return errorRes(500, "Error creating an UUID", err)
|
||||||
|
}
|
||||||
|
gist.Uuid = strings.Replace(uuidGist.String(), "-", "", -1)
|
||||||
|
|
||||||
|
gist.UserID = user.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
if gist.Title == "" {
|
||||||
|
if ctx.Request().PostForm["name"][0] == "" {
|
||||||
|
gist.Title = "gist:" + gist.Uuid
|
||||||
|
} else {
|
||||||
|
gist.Title = ctx.Request().PostForm["name"][0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(gist.Files) > 0 {
|
if len(gist.Files) > 0 {
|
||||||
split := strings.Split(gist.Files[0].Content, "\n")
|
split := strings.Split(gist.Files[0].Content, "\n")
|
||||||
if len(split) > 10 {
|
if len(split) > 10 {
|
||||||
|
@ -359,11 +368,11 @@ func processCreate(ctx echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if isCreate {
|
if isCreate {
|
||||||
if err = models.CreateGist(gist); err != nil {
|
if err = gist.Create(); err != nil {
|
||||||
return errorRes(500, "Error creating the gist", err)
|
return errorRes(500, "Error creating the gist", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = models.UpdateGist(gist); err != nil {
|
if err = gist.Update(); err != nil {
|
||||||
return errorRes(500, "Error updating the gist", err)
|
return errorRes(500, "Error updating the gist", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -375,7 +384,7 @@ func toggleVisibility(ctx echo.Context) error {
|
||||||
var gist = getData(ctx, "gist").(*models.Gist)
|
var gist = getData(ctx, "gist").(*models.Gist)
|
||||||
|
|
||||||
gist.Private = !gist.Private
|
gist.Private = !gist.Private
|
||||||
if err := models.UpdateGist(gist); err != nil {
|
if err := gist.Update(); err != nil {
|
||||||
return errorRes(500, "Error updating this gist", err)
|
return errorRes(500, "Error updating this gist", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +400,7 @@ func deleteGist(ctx echo.Context) error {
|
||||||
return errorRes(500, "Error deleting the repository", err)
|
return errorRes(500, "Error deleting the repository", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.DeleteGist(gist); err != nil {
|
if err := gist.Delete(); err != nil {
|
||||||
return errorRes(500, "Error deleting this gist", err)
|
return errorRes(500, "Error deleting this gist", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,15 +412,15 @@ func like(ctx echo.Context) error {
|
||||||
var gist = getData(ctx, "gist").(*models.Gist)
|
var gist = getData(ctx, "gist").(*models.Gist)
|
||||||
currentUser := getUserLogged(ctx)
|
currentUser := getUserLogged(ctx)
|
||||||
|
|
||||||
hasLiked, err := models.UserHasLikedGist(currentUser, gist)
|
hasLiked, err := currentUser.HasLiked(gist)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorRes(500, "Error checking if user has liked a gist", err)
|
return errorRes(500, "Error checking if user has liked a gist", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasLiked {
|
if hasLiked {
|
||||||
err = models.RemoveUserLike(gist, getUserLogged(ctx))
|
err = gist.RemoveUserLike(getUserLogged(ctx))
|
||||||
} else {
|
} else {
|
||||||
err = models.AppendUserLike(gist, getUserLogged(ctx))
|
err = gist.AppendUserLike(getUserLogged(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -429,7 +438,7 @@ func fork(ctx echo.Context) error {
|
||||||
var gist = getData(ctx, "gist").(*models.Gist)
|
var gist = getData(ctx, "gist").(*models.Gist)
|
||||||
currentUser := getUserLogged(ctx)
|
currentUser := getUserLogged(ctx)
|
||||||
|
|
||||||
alreadyForked, err := models.GetForkedGist(gist, currentUser)
|
alreadyForked, err := gist.GetForkParent(currentUser)
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return errorRes(500, "Error checking if gist is already forked", err)
|
return errorRes(500, "Error checking if gist is already forked", err)
|
||||||
}
|
}
|
||||||
|
@ -459,14 +468,14 @@ func fork(ctx echo.Context) error {
|
||||||
ForkedID: gist.ID,
|
ForkedID: gist.ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = models.CreateForkedGist(newGist); err != nil {
|
if err = newGist.CreateForked(); err != nil {
|
||||||
return errorRes(500, "Error forking the gist in database", err)
|
return errorRes(500, "Error forking the gist in database", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = git.ForkClone(gist.User.Username, gist.Uuid, currentUser.Username, newGist.Uuid); err != nil {
|
if err = git.ForkClone(gist.User.Username, gist.Uuid, currentUser.Username, newGist.Uuid); err != nil {
|
||||||
return errorRes(500, "Error cloning the repository while forking", err)
|
return errorRes(500, "Error cloning the repository while forking", err)
|
||||||
}
|
}
|
||||||
if err = models.IncrementGistForkCount(gist); err != nil {
|
if err = gist.IncrementForkCount(); err != nil {
|
||||||
return errorRes(500, "Error incrementing the fork count", err)
|
return errorRes(500, "Error incrementing the fork count", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,7 +576,7 @@ func likes(ctx echo.Context) error {
|
||||||
|
|
||||||
pageInt := getPage(ctx)
|
pageInt := getPage(ctx)
|
||||||
|
|
||||||
likers, err := models.GetUsersLikesForGist(gist, pageInt-1)
|
likers, err := gist.GetUsersLikes(pageInt - 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorRes(500, "Error getting users who liked this gist", err)
|
return errorRes(500, "Error getting users who liked this gist", err)
|
||||||
}
|
}
|
||||||
|
@ -591,7 +600,7 @@ func forks(ctx echo.Context) error {
|
||||||
fromUserID = currentUser.ID
|
fromUserID = currentUser.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
forks, err := models.GetUsersForksForGist(gist, fromUserID, pageInt-1)
|
forks, err := gist.GetForks(fromUserID, pageInt-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorRes(500, "Error getting users who liked this gist", err)
|
return errorRes(500, "Error getting users who liked this gist", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ func pack(ctx echo.Context, serviceType string) error {
|
||||||
|
|
||||||
// updatedAt is updated only if serviceType is receive-pack
|
// updatedAt is updated only if serviceType is receive-pack
|
||||||
if serviceType == "receive-pack" {
|
if serviceType == "receive-pack" {
|
||||||
_ = models.GistLastActiveNow(getData(ctx, "gist").(*models.Gist).ID)
|
_ = getData(ctx, "gist").(*models.Gist).SetLastActiveNow()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ func Start() {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
e.Use(middleware.Recover())
|
//e.Use(middleware.Recover())
|
||||||
e.Use(middleware.Secure())
|
e.Use(middleware.Secure())
|
||||||
|
|
||||||
e.Renderer = &Template{
|
e.Renderer = &Template{
|
||||||
|
@ -148,8 +148,8 @@ func Start() {
|
||||||
g3 := g1.Group("/:user/:gistname")
|
g3 := g1.Group("/:user/:gistname")
|
||||||
{
|
{
|
||||||
g3.Use(gistInit)
|
g3.Use(gistInit)
|
||||||
g3.GET("", gist)
|
g3.GET("", gistIndex)
|
||||||
g3.GET("/rev/:revision", gist)
|
g3.GET("/rev/:revision", gistIndex)
|
||||||
g3.GET("/revisions", revisions)
|
g3.GET("/revisions", revisions)
|
||||||
g3.GET("/archive/:revision", downloadZip)
|
g3.GET("/archive/:revision", downloadZip)
|
||||||
g3.POST("/visibility", toggleVisibility, logged, writePermission)
|
g3.POST("/visibility", toggleVisibility, logged, writePermission)
|
||||||
|
@ -203,8 +203,10 @@ func sessionInit(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(ctx echo.Context) error {
|
return func(ctx echo.Context) error {
|
||||||
sess := getSession(ctx)
|
sess := getSession(ctx)
|
||||||
if sess.Values["user"] != nil {
|
if sess.Values["user"] != nil {
|
||||||
user := &models.User{ID: sess.Values["user"].(uint)}
|
var err error
|
||||||
if err := models.GetLoginUserById(user); err != nil {
|
var user *models.User
|
||||||
|
|
||||||
|
if user, err = models.GetUserById(sess.Values["user"].(uint)); err != nil {
|
||||||
sess.Values["user"] = nil
|
sess.Values["user"] = nil
|
||||||
saveSession(sess, ctx)
|
saveSession(sess, ctx)
|
||||||
setData(ctx, "userLogged", nil)
|
setData(ctx, "userLogged", nil)
|
||||||
|
@ -232,7 +234,7 @@ func writePermission(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(ctx echo.Context) error {
|
return func(ctx echo.Context) error {
|
||||||
gist := getData(ctx, "gist")
|
gist := getData(ctx, "gist")
|
||||||
user := getUserLogged(ctx)
|
user := getUserLogged(ctx)
|
||||||
if !models.UserCanWrite(user, gist.(*models.Gist)) {
|
if !gist.(*models.Gist).CanWrite(user) {
|
||||||
return redirect(ctx, "/"+gist.(*models.Gist).User.Username+"/"+gist.(*models.Gist).Uuid)
|
return redirect(ctx, "/"+gist.(*models.Gist).User.Username+"/"+gist.(*models.Gist).Uuid)
|
||||||
}
|
}
|
||||||
return next(ctx)
|
return next(ctx)
|
||||||
|
|
|
@ -27,15 +27,16 @@ func sshKeysProcess(ctx echo.Context) error {
|
||||||
|
|
||||||
user := getUserLogged(ctx)
|
user := getUserLogged(ctx)
|
||||||
|
|
||||||
var key = new(models.SSHKey)
|
var dto = new(models.SSHKeyDTO)
|
||||||
if err := ctx.Bind(key); err != nil {
|
if err := ctx.Bind(dto); err != nil {
|
||||||
return errorRes(400, "Cannot bind data", err)
|
return errorRes(400, "Cannot bind data", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ctx.Validate(key); err != nil {
|
if err := ctx.Validate(dto); err != nil {
|
||||||
addFlash(ctx, validationMessages(&err), "error")
|
addFlash(ctx, validationMessages(&err), "error")
|
||||||
return redirect(ctx, "/ssh-keys")
|
return redirect(ctx, "/ssh-keys")
|
||||||
}
|
}
|
||||||
|
key := dto.ToSSHKey()
|
||||||
|
|
||||||
key.UserID = user.ID
|
key.UserID = user.ID
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ func sshKeysProcess(ctx echo.Context) error {
|
||||||
sha := sha256.Sum256(pubKey.Marshal())
|
sha := sha256.Sum256(pubKey.Marshal())
|
||||||
key.SHA = base64.StdEncoding.EncodeToString(sha[:])
|
key.SHA = base64.StdEncoding.EncodeToString(sha[:])
|
||||||
|
|
||||||
if err := models.AddSSHKey(key); err != nil {
|
if err := key.Create(); err != nil {
|
||||||
return errorRes(500, "Cannot add SSH key", err)
|
return errorRes(500, "Cannot add SSH key", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ func sshKeysDelete(ctx echo.Context) error {
|
||||||
return redirect(ctx, "/ssh-keys")
|
return redirect(ctx, "/ssh-keys")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.RemoveSSHKey(key); err != nil {
|
if err := key.Delete(); err != nil {
|
||||||
return errorRes(500, "Cannot delete SSH key", err)
|
return errorRes(500, "Cannot delete SSH key", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue