add news events
This commit is contained in:
parent
f8ecd20220
commit
2f05a2f8e7
6
api/api.go
Normal file
6
api/api.go
Normal file
@ -0,0 +1,6 @@
|
||||
package api
|
||||
|
||||
type BaseGetListRequest struct {
|
||||
Page int32 `form:"page" binding:"required,min=1"`
|
||||
PageSize int32 `form:"page_size" binding:"required,min=5"`
|
||||
}
|
71
api/news_event.go
Normal file
71
api/news_event.go
Normal file
@ -0,0 +1,71 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
|
||||
db "git.nochill.in/nochill/hiling_go/db/sqlc"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type CreateNewsEventsReq struct {
|
||||
Url string `json:"url" binding:"required,url"`
|
||||
Title string `json:"title" binding:"required"`
|
||||
Source string `json:"source"`
|
||||
Description string `json:"description"`
|
||||
SubmittedBy int32 `json:"submitted_by" binding:"required,numeric"`
|
||||
}
|
||||
|
||||
func (server *Server) createNews(ctx *gin.Context) {
|
||||
var req CreateNewsEventsReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, ValidationErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
err := server.Store.CreateNewsEvents(ctx, db.CreateNewsEventsParams{
|
||||
Title: req.Title,
|
||||
Url: req.Url,
|
||||
Source: req.Source,
|
||||
Description: sql.NullString{Valid: len(req.Description) > 0, String: req.Description},
|
||||
SubmittedBy: req.SubmittedBy,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to save news/evnts"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Writer.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
|
||||
type GetNewsEventsListReq struct {
|
||||
BaseGetListRequest
|
||||
Approved int8 `form:"is_with_approval"`
|
||||
}
|
||||
|
||||
func (server *Server) GetNewsEventsList(ctx *gin.Context) {
|
||||
var req GetNewsEventsListReq
|
||||
isWithApproval := ""
|
||||
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, ValidationErrorResponse(err))
|
||||
return
|
||||
}
|
||||
if req.Approved > 0 {
|
||||
isWithApproval = "WHERE approved_by IS NOT NULL"
|
||||
}
|
||||
|
||||
news, err := server.Store.GetNewsEventsList(ctx, db.GetNewsEventsListParams{
|
||||
Limit: req.PageSize,
|
||||
Offset: (req.Page - 1) * req.PageSize,
|
||||
IsWithApproved: isWithApproval,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to get news / events"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, news)
|
||||
}
|
@ -43,8 +43,6 @@ func (server *Server) getRoutes() {
|
||||
AllowMethods: []string{"POST", "PUT", "GET", "DELETE", "PATCH"},
|
||||
}))
|
||||
|
||||
// router.Use(CORSMiddleware())
|
||||
|
||||
router.POST("/user/signup", server.createUser)
|
||||
router.POST("/user/login", server.login)
|
||||
router.POST("/user/logout", server.logout)
|
||||
@ -64,6 +62,9 @@ func (server *Server) getRoutes() {
|
||||
//IMAGES
|
||||
router.GET("/images/location", server.getAllImagesByLocation)
|
||||
|
||||
// NEWS / EVENTS
|
||||
router.GET("/news-events", server.GetNewsEventsList)
|
||||
|
||||
// REQUIRE AUTH TOKEN
|
||||
authRoutes := router.Use(authMiddleware(server.TokenMaker))
|
||||
authRoutes.POST("/review/location", server.createReview)
|
||||
@ -72,6 +73,7 @@ func (server *Server) getRoutes() {
|
||||
authRoutes.GET("/user/profile", server.getUserStats)
|
||||
authRoutes.PATCH("/user/avatar", server.updateUserAvatar)
|
||||
authRoutes.DELETE("/user/avatar", server.removeAvatar)
|
||||
authRoutes.POST("/news-events", server.createNews)
|
||||
|
||||
server.Router = router
|
||||
}
|
||||
|
1
db/migrations/000010_create_news_event_table.down.sql
Normal file
1
db/migrations/000010_create_news_event_table.down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS news_events;
|
13
db/migrations/000010_create_news_event_table.up.sql
Normal file
13
db/migrations/000010_create_news_event_table.up.sql
Normal file
@ -0,0 +1,13 @@
|
||||
CREATE TABLE news_events (
|
||||
"id" serial primary key not null,
|
||||
"title" varchar not null,
|
||||
"url" varchar not null,
|
||||
"source" varchar not null,
|
||||
"thumbnail" varchar,
|
||||
"description" text,
|
||||
"is_deleted" boolean not null default(false),
|
||||
"submitted_by" int references "users"("id") not null,
|
||||
"approved_by" int references "users"("id"),
|
||||
"created_at" timestamp default(now()),
|
||||
"updated_at" timestamp default(now())
|
||||
)
|
@ -108,6 +108,20 @@ func (mr *MockStoreMockRecorder) CreateLocationTx(arg0, arg1 interface{}) *gomoc
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateLocationTx", reflect.TypeOf((*MockStore)(nil).CreateLocationTx), arg0, arg1)
|
||||
}
|
||||
|
||||
// CreateNewsEvents mocks base method.
|
||||
func (m *MockStore) CreateNewsEvents(arg0 context.Context, arg1 db.CreateNewsEventsParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateNewsEvents", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreateNewsEvents indicates an expected call of CreateNewsEvents.
|
||||
func (mr *MockStoreMockRecorder) CreateNewsEvents(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNewsEvents", reflect.TypeOf((*MockStore)(nil).CreateNewsEvents), arg0, arg1)
|
||||
}
|
||||
|
||||
// CreateReview mocks base method.
|
||||
func (m *MockStore) CreateReview(arg0 context.Context, arg1 db.CreateReviewParams) (db.Review, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -303,6 +317,21 @@ func (mr *MockStoreMockRecorder) GetLocationTag(arg0, arg1 interface{}) *gomock.
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLocationTag", reflect.TypeOf((*MockStore)(nil).GetLocationTag), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetNewsEventsList mocks base method.
|
||||
func (m *MockStore) GetNewsEventsList(arg0 context.Context, arg1 db.GetNewsEventsListParams) ([]db.NewsEventRow, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetNewsEventsList", arg0, arg1)
|
||||
ret0, _ := ret[0].([]db.NewsEventRow)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetNewsEventsList indicates an expected call of GetNewsEventsList.
|
||||
func (mr *MockStoreMockRecorder) GetNewsEventsList(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNewsEventsList", reflect.TypeOf((*MockStore)(nil).GetNewsEventsList), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetSession mocks base method.
|
||||
func (m *MockStore) GetSession(arg0 context.Context, arg1 int32) (db.UserSession, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
8
db/queries/news_events.sql
Normal file
8
db/queries/news_events.sql
Normal file
@ -0,0 +1,8 @@
|
||||
-- name: CreateNewsEvents :exec
|
||||
INSERT INTO news_events(
|
||||
title,
|
||||
url,
|
||||
source,
|
||||
description,
|
||||
submitted_by
|
||||
) VALUES ( $1, $2, $3, $4, $5);
|
@ -46,9 +46,9 @@ func (q *Queries) GetTopListLocations(ctx context.Context, arg GetTopListLocatio
|
||||
FROM(
|
||||
SELECT
|
||||
*,
|
||||
(SELECT 5 * 4 + COALESCE(critic_score, 0) * COALESCE(critic_count, 0) / 5 + COALESCE(critic_count, 0)) as critic_bayes,
|
||||
(SELECT 50 + COALESCE(user_score, 0) * COALESCE(user_count, 0) / 50 + COALESCE(user_count, 0)) as user_bayes,
|
||||
((SELECT 50 + COALESCE(user_score, 0) * COALESCE(user_count, 0) / 50 + COALESCE(user_count, 0)) + (SELECT 5 * 4 + COALESCE(critic_score, 0) * COALESCE(critic_count, 0) / 5 + COALESCE(critic_count, 0)) ) / 2 as avg_bayes
|
||||
(SELECT 5 * 5 + COALESCE(critic_score, 0) * COALESCE(critic_count, 0) / 5 + COALESCE(critic_count, 0)) as critic_bayes,
|
||||
(SELECT 5 * 5 + COALESCE(user_score, 0) * COALESCE(user_count, 0) / 5 + COALESCE(user_count, 0)) as user_bayes,
|
||||
((SELECT 5 * 5 + COALESCE(user_score, 0) * COALESCE(user_count, 0) / 50 + COALESCE(user_count, 0)) + (SELECT 5 * 5 + COALESCE(critic_score, 0) * COALESCE(critic_count, 0) / 5 + COALESCE(critic_count, 0)) ) / 2 as avg_bayes
|
||||
|
||||
FROM (
|
||||
SELECT
|
||||
|
@ -206,6 +206,20 @@ type LocationImage struct {
|
||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||
}
|
||||
|
||||
type NewsEvent struct {
|
||||
ID int32 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Url string `json:"url"`
|
||||
Source string `json:"source"`
|
||||
Thumbnail sql.NullString `json:"thumbnail"`
|
||||
Description sql.NullString `json:"description"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
SubmittedBy int32 `json:"submitted_by"`
|
||||
ApprovedBy sql.NullInt32 `json:"approved_by"`
|
||||
CreatedAt sql.NullTime `json:"created_at"`
|
||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||
}
|
||||
|
||||
type Province struct {
|
||||
ID int32 `json:"id"`
|
||||
ProvinceName string `json:"province_name"`
|
||||
|
87
db/sqlc/news_events.go
Normal file
87
db/sqlc/news_events.go
Normal file
@ -0,0 +1,87 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GetNewsEventsListParams struct {
|
||||
Limit int32
|
||||
Offset int32
|
||||
IsWithApproved string
|
||||
}
|
||||
|
||||
type NewsEventRow struct {
|
||||
ID int32 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Url string `json:"url"`
|
||||
Source string `json:"source"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Description string `json:"description"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
SubmittedBy string `json:"submitted_by"`
|
||||
ApprovedBy int32 `json:"approved_by"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetNewsEventsList(ctx context.Context, arg GetNewsEventsListParams) ([]NewsEventRow, error) {
|
||||
getNewsEventsListQ := fmt.Sprintf(`
|
||||
SELECT
|
||||
n.id,
|
||||
n.title,
|
||||
n.url,
|
||||
n.source,
|
||||
COALESCE(n.thumbnail, '') as thumbnail,
|
||||
COALESCE(n.description, '') as description,
|
||||
n.is_deleted,
|
||||
u.username as submitted_by,
|
||||
COALESCE(n.approved_by, 0) as approved_by,
|
||||
n.created_at,
|
||||
n.updated_at
|
||||
FROM news_events n
|
||||
JOIN users u ON n.submitted_by = u.id
|
||||
%s
|
||||
ORDER BY n.created_at DESC
|
||||
LIMIT $1
|
||||
OFFSET $2
|
||||
`, arg.IsWithApproved)
|
||||
|
||||
rows, err := q.db.QueryContext(ctx, getNewsEventsListQ, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
items := []NewsEventRow{}
|
||||
|
||||
for rows.Next() {
|
||||
var i NewsEventRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Title,
|
||||
&i.Url,
|
||||
&i.Source,
|
||||
&i.Thumbnail,
|
||||
&i.Description,
|
||||
&i.IsDeleted,
|
||||
&i.SubmittedBy,
|
||||
&i.ApprovedBy,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items = append(items, i)
|
||||
}
|
||||
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
40
db/sqlc/news_events.sql.go
Normal file
40
db/sqlc/news_events.sql.go
Normal file
@ -0,0 +1,40 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.20.0
|
||||
// source: news_events.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
const createNewsEvents = `-- name: CreateNewsEvents :exec
|
||||
INSERT INTO news_events(
|
||||
title,
|
||||
url,
|
||||
source,
|
||||
description,
|
||||
submitted_by
|
||||
) VALUES ( $1, $2, $3, $4, $5)
|
||||
`
|
||||
|
||||
type CreateNewsEventsParams struct {
|
||||
Title string `json:"title"`
|
||||
Url string `json:"url"`
|
||||
Source string `json:"source"`
|
||||
Description sql.NullString `json:"description"`
|
||||
SubmittedBy int32 `json:"submitted_by"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateNewsEvents(ctx context.Context, arg CreateNewsEventsParams) error {
|
||||
_, err := q.db.ExecContext(ctx, createNewsEvents,
|
||||
arg.Title,
|
||||
arg.Url,
|
||||
arg.Source,
|
||||
arg.Description,
|
||||
arg.SubmittedBy,
|
||||
)
|
||||
return err
|
||||
}
|
@ -12,6 +12,7 @@ import (
|
||||
type Querier interface {
|
||||
AddFollowUser(ctx context.Context, arg AddFollowUserParams) error
|
||||
CheckIfReviewExists(ctx context.Context, arg CheckIfReviewExistsParams) (int64, error)
|
||||
CreateNewsEvents(ctx context.Context, arg CreateNewsEventsParams) error
|
||||
CreateSession(ctx context.Context, arg CreateSessionParams) (UserSession, error)
|
||||
CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
|
||||
GetCountImageByLocation(ctx context.Context, imageOf int32) (int64, error)
|
||||
|
@ -21,6 +21,7 @@ type Store interface {
|
||||
CreateLocation(ctx context.Context, arg CreateLocationParams) (int32, error)
|
||||
CreateImage(ctx context.Context, arg []CreateImageParams) error
|
||||
CreateLocationTx(ctx context.Context, arg CreateLocationTxParams) error
|
||||
GetNewsEventsList(ctx context.Context, arg GetNewsEventsListParams) ([]NewsEventRow, error)
|
||||
}
|
||||
|
||||
type SQLStore struct {
|
||||
|
Loading…
Reference in New Issue
Block a user