mirror of
https://github.com/yanislav-igonin/micrach
synced 2024-12-22 14:22:33 +03:00
Feature- Bump limit (#9)
* feat: add bump limit check on thread update * feat: add captcha is active env var
This commit is contained in:
parent
868a7214d2
commit
2bcd0ff8c3
@ -4,3 +4,5 @@ SEED_DB=true
|
||||
IS_RATE_LIMITER_ENABLED=true
|
||||
THREADS_MAX_COUNT=50
|
||||
POSTGRES_URL=postgres://localhost/micrach?pool_max_conns=5
|
||||
THREAD_BUMP_LIMIT=500
|
||||
IS_CAPTCHA_ACTIVE=true
|
@ -13,6 +13,8 @@ type AppConfig struct {
|
||||
SeedDb bool
|
||||
IsRateLimiterEnabled bool
|
||||
ThreadsMaxCount int
|
||||
ThreadBumpLimit int
|
||||
IsCaptchaActive bool
|
||||
}
|
||||
|
||||
type DbConfig struct {
|
||||
@ -50,6 +52,8 @@ func getAppConfig() AppConfig {
|
||||
seedDb := getValueOrDefaultBoolean(os.Getenv("SEED_DB"), false)
|
||||
isRateLimiterEnabled := getValueOrDefaultBoolean(os.Getenv("IS_RATE_LIMITER_ENABLED"), true)
|
||||
threadsMaxCount := getValueOrDefaultInt(os.Getenv("THREADS_MAX_COUNT"), 50)
|
||||
threadBumpLimit := getValueOrDefaultInt(os.Getenv("THREAD_BUMP_LIMIT"), 500)
|
||||
isCaptchaActive := getValueOrDefaultBoolean(os.Getenv("IS_CAPTCHA_ACTIVE"), true)
|
||||
|
||||
return AppConfig{
|
||||
Env: env,
|
||||
@ -57,6 +61,8 @@ func getAppConfig() AppConfig {
|
||||
SeedDb: seedDb,
|
||||
IsRateLimiterEnabled: isRateLimiterEnabled,
|
||||
ThreadsMaxCount: threadsMaxCount,
|
||||
ThreadBumpLimit: threadBumpLimit,
|
||||
IsCaptchaActive: isCaptchaActive,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,8 @@ func GetThreads(c *gin.Context) {
|
||||
PagesCount: pagesCount,
|
||||
Page: page,
|
||||
FormData: Repositories.HtmlFormData{
|
||||
CaptchaID: captchaID,
|
||||
CaptchaID: captchaID,
|
||||
IsCaptchaActive: Config.App.IsCaptchaActive,
|
||||
},
|
||||
}
|
||||
c.HTML(http.StatusOK, "index.html", htmlData)
|
||||
@ -87,8 +88,9 @@ func GetThread(c *gin.Context) {
|
||||
htmlData := Repositories.GetThreadHtmlData{
|
||||
Thread: thread,
|
||||
FormData: Repositories.HtmlFormData{
|
||||
FirstPostID: firstPost.ID,
|
||||
CaptchaID: captchaID,
|
||||
FirstPostID: firstPost.ID,
|
||||
CaptchaID: captchaID,
|
||||
IsCaptchaActive: Config.App.IsCaptchaActive,
|
||||
},
|
||||
}
|
||||
c.HTML(http.StatusOK, "thread.html", htmlData)
|
||||
@ -309,6 +311,11 @@ func UpdateThread(c *gin.Context) {
|
||||
}
|
||||
defer tx.Rollback(context.TODO())
|
||||
|
||||
if err != nil {
|
||||
log.Println("error:", err)
|
||||
c.HTML(http.StatusInternalServerError, "500.html", nil)
|
||||
return
|
||||
}
|
||||
post := Repositories.Post{
|
||||
IsParent: false,
|
||||
ParentID: threadID,
|
||||
@ -323,6 +330,23 @@ func UpdateThread(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
postsCountInThread, err := Repositories.Posts.GetThreadPostsCount(threadID)
|
||||
if err != nil {
|
||||
log.Println("error:", err)
|
||||
c.HTML(http.StatusInternalServerError, "500.html", nil)
|
||||
return
|
||||
}
|
||||
isBumpLimit := postsCountInThread >= Config.App.ThreadBumpLimit
|
||||
isThreadBumped := !isBumpLimit && !isSage && !post.IsParent
|
||||
if isThreadBumped {
|
||||
err = Repositories.Posts.BumpThreadInTx(tx, threadID)
|
||||
if err != nil {
|
||||
log.Println("error:", err)
|
||||
c.HTML(http.StatusInternalServerError, "500.html", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, fileInRequest := range filesInRequest {
|
||||
file := Repositories.File{
|
||||
PostID: postID,
|
||||
|
@ -208,23 +208,6 @@ func (r *PostsRepository) CreateInTx(tx pgx.Tx, p Post) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// updating parent post `updated_at`
|
||||
if !p.IsParent && !p.IsSage {
|
||||
sql = `
|
||||
UPDATE posts
|
||||
SET updated_at = now()
|
||||
WHERE id = $1
|
||||
`
|
||||
row := tx.QueryRow(context.TODO(), sql, p.ParentID)
|
||||
var msg string
|
||||
err = row.Scan(&msg)
|
||||
// UPDATE always return `no rows`
|
||||
// so we need to check this condition
|
||||
if err != nil && err != pgx.ErrNoRows {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return createdPost.ID, nil
|
||||
}
|
||||
|
||||
@ -263,3 +246,34 @@ func (r *PostsRepository) ArchiveThreadsFrom(t time.Time) error {
|
||||
_, err := Db.Pool.Exec(context.TODO(), sql, t)
|
||||
return err
|
||||
}
|
||||
|
||||
// Returns count of posts in thread by thread ID
|
||||
func (r *PostsRepository) GetThreadPostsCount(id int) (int, error) {
|
||||
sql := `
|
||||
SELECT COUNT(*)
|
||||
FROM posts
|
||||
WHERE
|
||||
(id = $1 AND is_parent = true AND is_deleted != true)
|
||||
OR (parent_id = $1 AND is_deleted != true)
|
||||
`
|
||||
|
||||
row := Db.Pool.QueryRow(context.TODO(), sql, id)
|
||||
var count int
|
||||
err := row.Scan(&count)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// Updates threads updated at time by thread ID
|
||||
func (r *PostsRepository) BumpThreadInTx(tx pgx.Tx, id int) error {
|
||||
sql := `
|
||||
UPDATE posts
|
||||
SET updated_at = now()
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
_, err := tx.Query(context.TODO(), sql, id)
|
||||
return err
|
||||
}
|
||||
|
@ -34,8 +34,9 @@ type File struct {
|
||||
|
||||
// post-form.html
|
||||
type HtmlFormData struct {
|
||||
FirstPostID int
|
||||
CaptchaID string
|
||||
FirstPostID int
|
||||
CaptchaID string
|
||||
IsCaptchaActive bool
|
||||
}
|
||||
|
||||
// thread.html
|
||||
|
@ -15,11 +15,13 @@
|
||||
<textarea class="form-control" id="postText" rows="5" placeholder="Text" name="text"></textarea>
|
||||
<input class="form-control" type="file" id="postFiles" multiple name="files">
|
||||
|
||||
{{ if .IsCaptchaActive }}
|
||||
<div class="captcha-container text-center">
|
||||
<img src="/captcha/{{ .CaptchaID }}" alt="Captcha">
|
||||
</div>
|
||||
<input class="form-control" type="hidden" name="captchaId" value="{{ .CaptchaID }}">
|
||||
<input class="form-control" id="postCaptcha" type="tel" pattern="\d+" placeholder="Captcha" name="captcha">
|
||||
{{ end }}
|
||||
|
||||
<div class="row">
|
||||
{{ if ne .FirstPostID 0 }}
|
||||
|
Loading…
Reference in New Issue
Block a user