Skip to content

Commit

Permalink
Search gists (thomiceli#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomiceli committed Jun 21, 2023
1 parent 98c5cd1 commit 7b5d035
Show file tree
Hide file tree
Showing 10 changed files with 334 additions and 74 deletions.
10 changes: 9 additions & 1 deletion internal/models/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ func Setup(dbPath string) error {
return err
}

if err = db.AutoMigrate(&User{}, &SSHKey{}, &Gist{}, &AdminSetting{}); err != nil {
if err = db.SetupJoinTable(&Gist{}, "Likes", &Like{}); err != nil {
return err
}

if err = db.SetupJoinTable(&User{}, "Liked", &Like{}); err != nil {
return err
}

if err = db.AutoMigrate(&User{}, &Gist{}, &SSHKey{}, &AdminSetting{}); err != nil {
return err
}

Expand Down
80 changes: 77 additions & 3 deletions internal/models/gist.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ type Gist struct {
ForkedID uint
}

type Like struct {
UserID uint `gorm:"primaryKey"`
GistID uint `gorm:"primaryKey"`
CreatedAt int64
}

func (gist *Gist) BeforeDelete(tx *gorm.DB) error {
// Decrement fork counter if the gist was forked
err := tx.Model(&Gist{}).
Expand Down Expand Up @@ -80,11 +86,11 @@ func GetAllGists(offset int) ([]*Gist, error) {
return gists, err
}

func GetAllGistsFromUser(fromUser string, currentUserId uint, offset int, sort string, order string) ([]*Gist, error) {
func GetAllGistsFromSearch(currentUserId uint, query string, offset int, sort string, order string) ([]*Gist, error) {
var gists []*Gist
err := db.Preload("User").Preload("Forked.User").
Where("users.username = ? and ((gists.private = 0) or (gists.private = 1 and gists.user_id = ?))", fromUser, currentUserId).
Joins("join users on gists.user_id = users.id").
Where("((gists.private = 0) or (gists.private = 1 and gists.user_id = ?))", currentUserId).
Where("gists.title like ? or gists.description like ?", "%"+query+"%", "%"+query+"%").
Limit(11).
Offset(offset * 10).
Order("gists." + sort + "_at " + order).
Expand All @@ -93,6 +99,74 @@ func GetAllGistsFromUser(fromUser string, currentUserId uint, offset int, sort s
return gists, err
}

func gistsFromUserStatement(fromUserId uint, currentUserId uint) *gorm.DB {
return db.Preload("User").Preload("Forked.User").
Where("((gists.private = 0) or (gists.private = 1 and gists.user_id = ?))", currentUserId).
Where("users.id = ?", fromUserId).
Joins("join users on gists.user_id = users.id")
}

func GetAllGistsFromUser(fromUserId uint, currentUserId uint, offset int, sort string, order string) ([]*Gist, error) {
var gists []*Gist
err := gistsFromUserStatement(fromUserId, currentUserId).Limit(11).
Offset(offset * 10).
Order("gists." + sort + "_at " + order).
Find(&gists).Error

return gists, err
}

func CountAllGistsFromUser(fromUserId uint, currentUserId uint) (int64, error) {
var count int64
err := gistsFromUserStatement(fromUserId, currentUserId).Model(&Gist{}).Count(&count).Error
return count, err
}

func likedStatement(fromUserId uint, currentUserId uint) *gorm.DB {
return db.Preload("User").Preload("Forked.User").
Where("((gists.private = 0) or (gists.private = 1 and gists.user_id = ?))", currentUserId).
Where("likes.user_id = ?", fromUserId).
Joins("join likes on gists.id = likes.gist_id").
Joins("join users on likes.user_id = users.id")
}

func GetAllGistsLikedByUser(fromUserId uint, currentUserId uint, offset int, sort string, order string) ([]*Gist, error) {
var gists []*Gist
err := likedStatement(fromUserId, currentUserId).Limit(11).
Offset(offset * 10).
Order("gists." + sort + "_at " + order).
Find(&gists).Error
return gists, err
}

func CountAllGistsLikedByUser(fromUserId uint, currentUserId uint) (int64, error) {
var count int64
err := likedStatement(fromUserId, currentUserId).Model(&Gist{}).Count(&count).Error
return count, err
}

func forkedStatement(fromUserId uint, currentUserId uint) *gorm.DB {
return db.Preload("User").Preload("Forked.User").
Where("gists.forked_id is not null and ((gists.private = 0) or (gists.private = 1 and gists.user_id = ?))", currentUserId).
Where("gists.user_id = ?", fromUserId).
Joins("join users on gists.user_id = users.id")
}

func GetAllGistsForkedByUser(fromUserId uint, currentUserId uint, offset int, sort string, order string) ([]*Gist, error) {
var gists []*Gist
err := forkedStatement(fromUserId, currentUserId).Limit(11).
Offset(offset * 10).
Order("gists." + sort + "_at " + order).
Find(&gists).Error
return gists, err
}

func CountAllGistsForkedByUser(fromUserId uint, currentUserId uint) (int64, error) {
var count int64
err := forkedStatement(fromUserId, currentUserId).Model(&Gist{}).Count(&count).Error
return count, err
}

func GetAllGistsRows() ([]*Gist, error) {
var gists []*Gist
err := db.Table("gists").
Expand Down
1 change: 0 additions & 1 deletion internal/web/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,6 @@ func urlJoin(base string, elem ...string) string {
}

func getAvatarUrlFromProvider(provider string, identifier string) string {
fmt.Println("getAvatarUrlFromProvider", provider, identifier)
switch provider {
case "github":
return "https://avatars.githubusercontent.com/u/" + identifier + "?v=4"
Expand Down
74 changes: 66 additions & 8 deletions internal/web/gist.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"gorm.io/gorm"
"html/template"
"net/url"
"regexp"
"strconv"
"strings"
)
Expand Down Expand Up @@ -85,10 +86,10 @@ func gistInit(next echo.HandlerFunc) echo.HandlerFunc {

func allGists(ctx echo.Context) error {
var err error
fromUserStr := ctx.Param("user")
var urlPage string

fromUserStr := ctx.Param("user")
userLogged := getUserLogged(ctx)

pageInt := getPage(ctx)

sort := "created"
Expand All @@ -114,14 +115,37 @@ func allGists(ctx echo.Context) error {
} else {
currentUserId = 0
}

if fromUserStr == "" {
setData(ctx, "htmlTitle", "All gists")
fromUserStr = "all"
gists, err = models.GetAllGistsForCurrentUser(currentUserId, pageInt-1, sort, order)
urlctx := ctx.Request().URL.Path
if strings.HasSuffix(urlctx, "search") {
setData(ctx, "htmlTitle", "Search results")
setData(ctx, "mode", "search")
setData(ctx, "searchQuery", template.URL("&q="+ctx.QueryParam("q")))
urlPage = "search"
gists, err = models.GetAllGistsFromSearch(currentUserId, ctx.QueryParam("q"), pageInt-1, sort, order)
} else if strings.HasSuffix(urlctx, "all") {
setData(ctx, "htmlTitle", "All gists")
setData(ctx, "mode", "all")
urlPage = "all"
gists, err = models.GetAllGistsForCurrentUser(currentUserId, pageInt-1, sort, order)
}
} else {
setData(ctx, "htmlTitle", "All gists from "+fromUserStr)
liked := false
forked := false

liked, err = regexp.MatchString(`/[^/]*/liked`, ctx.Request().URL.Path)
if err != nil {
return errorRes(500, "Error matching regexp", err)
}

forked, err = regexp.MatchString(`/[^/]*/forked`, ctx.Request().URL.Path)
if err != nil {
return errorRes(500, "Error matching regexp", err)
}

var fromUser *models.User

fromUser, err = models.GetUserByUsername(fromUserStr)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
Expand All @@ -131,7 +155,40 @@ func allGists(ctx echo.Context) error {
}
setData(ctx, "fromUser", fromUser)

gists, err = models.GetAllGistsFromUser(fromUserStr, currentUserId, pageInt-1, sort, order)
if countFromUser, err := models.CountAllGistsFromUser(fromUser.ID, currentUserId); err != nil {
return errorRes(500, "Error counting gists", err)
} else {
setData(ctx, "countFromUser", countFromUser)
}

if countLiked, err := models.CountAllGistsLikedByUser(fromUser.ID, currentUserId); err != nil {
return errorRes(500, "Error counting liked gists", err)
} else {
setData(ctx, "countLiked", countLiked)
}

if countForked, err := models.CountAllGistsForkedByUser(fromUser.ID, currentUserId); err != nil {
return errorRes(500, "Error counting forked gists", err)
} else {
setData(ctx, "countForked", countForked)
}

if liked {
urlPage = fromUserStr + "/liked"
setData(ctx, "htmlTitle", "All gists liked by "+fromUserStr)
setData(ctx, "mode", "liked")
gists, err = models.GetAllGistsLikedByUser(fromUser.ID, currentUserId, pageInt-1, sort, order)
} else if forked {
urlPage = fromUserStr + "/forked"
setData(ctx, "htmlTitle", "All gists forked by "+fromUserStr)
setData(ctx, "mode", "forked")
gists, err = models.GetAllGistsForkedByUser(fromUser.ID, currentUserId, pageInt-1, sort, order)
} else {
urlPage = fromUserStr
setData(ctx, "htmlTitle", "All gists from "+fromUserStr)
setData(ctx, "mode", "fromUser")
gists, err = models.GetAllGistsFromUser(fromUser.ID, currentUserId, pageInt-1, sort, order)
}
}

if err != nil {
Expand All @@ -142,6 +199,7 @@ func allGists(ctx echo.Context) error {
return errorRes(404, "Page not found", nil)
}

setData(ctx, "urlPage", urlPage)
return html(ctx, "all.html")
}

Expand Down Expand Up @@ -527,7 +585,7 @@ func likes(ctx echo.Context) error {
return errorRes(404, "Page not found", nil)
}

setData(ctx, "htmlTitle", "Likes for "+gist.Title)
setData(ctx, "htmlTitle", "Like for "+gist.Title)
setData(ctx, "revision", "HEAD")
return html(ctx, "likes.html")
}
Expand Down
3 changes: 3 additions & 0 deletions internal/web/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,10 @@ func Start() {
}

g1.GET("/all", allGists, checkRequireLogin)
g1.GET("/search", allGists, checkRequireLogin)
g1.GET("/:user", allGists, checkRequireLogin)
g1.GET("/:user/liked", allGists, checkRequireLogin)
g1.GET("/:user/forked", allGists, checkRequireLogin)

g3 := g1.Group("/:user/:gistname")
{
Expand Down
2 changes: 1 addition & 1 deletion internal/web/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func validateReservedKeywords(fl validator.FieldLevel) bool {
name := fl.Field().String()

restrictedNames := map[string]struct{}{}
for _, restrictedName := range []string{"assets", "register", "login", "logout", "config", "admin-panel", "all"} {
for _, restrictedName := range []string{"assets", "register", "login", "logout", "settings", "admin-panel", "all", "search"} {
restrictedNames[restrictedName] = struct{}{}
}

Expand Down
4 changes: 4 additions & 0 deletions public/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ document.addEventListener('DOMContentLoaded', () => {
themeMenu.classList.toggle('hidden');
}

document.getElementById('user-btn')?.addEventListener("click" , (e) => {
document.getElementById('user-menu').classList.toggle('hidden');
})

document.querySelectorAll('.moment-timestamp').forEach((e: HTMLElement) => {
e.title = moment.unix(parseInt(e.innerHTML)).format('LLLL');
e.innerHTML = moment.unix(parseInt(e.innerHTML)).fromNow();
Expand Down
Loading

0 comments on commit 7b5d035

Please sign in to comment.