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"},
|
AllowMethods: []string{"POST", "PUT", "GET", "DELETE", "PATCH"},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// router.Use(CORSMiddleware())
|
|
||||||
|
|
||||||
router.POST("/user/signup", server.createUser)
|
router.POST("/user/signup", server.createUser)
|
||||||
router.POST("/user/login", server.login)
|
router.POST("/user/login", server.login)
|
||||||
router.POST("/user/logout", server.logout)
|
router.POST("/user/logout", server.logout)
|
||||||
@ -64,6 +62,9 @@ func (server *Server) getRoutes() {
|
|||||||
//IMAGES
|
//IMAGES
|
||||||
router.GET("/images/location", server.getAllImagesByLocation)
|
router.GET("/images/location", server.getAllImagesByLocation)
|
||||||
|
|
||||||
|
// NEWS / EVENTS
|
||||||
|
router.GET("/news-events", server.GetNewsEventsList)
|
||||||
|
|
||||||
// REQUIRE AUTH TOKEN
|
// REQUIRE AUTH TOKEN
|
||||||
authRoutes := router.Use(authMiddleware(server.TokenMaker))
|
authRoutes := router.Use(authMiddleware(server.TokenMaker))
|
||||||
authRoutes.POST("/review/location", server.createReview)
|
authRoutes.POST("/review/location", server.createReview)
|
||||||
@ -72,6 +73,7 @@ func (server *Server) getRoutes() {
|
|||||||
authRoutes.GET("/user/profile", server.getUserStats)
|
authRoutes.GET("/user/profile", server.getUserStats)
|
||||||
authRoutes.PATCH("/user/avatar", server.updateUserAvatar)
|
authRoutes.PATCH("/user/avatar", server.updateUserAvatar)
|
||||||
authRoutes.DELETE("/user/avatar", server.removeAvatar)
|
authRoutes.DELETE("/user/avatar", server.removeAvatar)
|
||||||
|
authRoutes.POST("/news-events", server.createNews)
|
||||||
|
|
||||||
server.Router = router
|
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)
|
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.
|
// CreateReview mocks base method.
|
||||||
func (m *MockStore) CreateReview(arg0 context.Context, arg1 db.CreateReviewParams) (db.Review, error) {
|
func (m *MockStore) CreateReview(arg0 context.Context, arg1 db.CreateReviewParams) (db.Review, error) {
|
||||||
m.ctrl.T.Helper()
|
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)
|
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.
|
// GetSession mocks base method.
|
||||||
func (m *MockStore) GetSession(arg0 context.Context, arg1 int32) (db.UserSession, error) {
|
func (m *MockStore) GetSession(arg0 context.Context, arg1 int32) (db.UserSession, error) {
|
||||||
m.ctrl.T.Helper()
|
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(
|
FROM(
|
||||||
SELECT
|
SELECT
|
||||||
*,
|
*,
|
||||||
(SELECT 5 * 4 + COALESCE(critic_score, 0) * COALESCE(critic_count, 0) / 5 + COALESCE(critic_count, 0)) as critic_bayes,
|
(SELECT 5 * 5 + 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 5 * 5 + COALESCE(user_score, 0) * COALESCE(user_count, 0) / 5 + 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(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 (
|
FROM (
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -206,6 +206,20 @@ type LocationImage struct {
|
|||||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
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 {
|
type Province struct {
|
||||||
ID int32 `json:"id"`
|
ID int32 `json:"id"`
|
||||||
ProvinceName string `json:"province_name"`
|
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 {
|
type Querier interface {
|
||||||
AddFollowUser(ctx context.Context, arg AddFollowUserParams) error
|
AddFollowUser(ctx context.Context, arg AddFollowUserParams) error
|
||||||
CheckIfReviewExists(ctx context.Context, arg CheckIfReviewExistsParams) (int64, error)
|
CheckIfReviewExists(ctx context.Context, arg CheckIfReviewExistsParams) (int64, error)
|
||||||
|
CreateNewsEvents(ctx context.Context, arg CreateNewsEventsParams) error
|
||||||
CreateSession(ctx context.Context, arg CreateSessionParams) (UserSession, error)
|
CreateSession(ctx context.Context, arg CreateSessionParams) (UserSession, error)
|
||||||
CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
|
CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
|
||||||
GetCountImageByLocation(ctx context.Context, imageOf int32) (int64, error)
|
GetCountImageByLocation(ctx context.Context, imageOf int32) (int64, error)
|
||||||
|
@ -21,6 +21,7 @@ type Store interface {
|
|||||||
CreateLocation(ctx context.Context, arg CreateLocationParams) (int32, error)
|
CreateLocation(ctx context.Context, arg CreateLocationParams) (int32, error)
|
||||||
CreateImage(ctx context.Context, arg []CreateImageParams) error
|
CreateImage(ctx context.Context, arg []CreateImageParams) error
|
||||||
CreateLocationTx(ctx context.Context, arg CreateLocationTxParams) error
|
CreateLocationTx(ctx context.Context, arg CreateLocationTxParams) error
|
||||||
|
GetNewsEventsList(ctx context.Context, arg GetNewsEventsListParams) ([]NewsEventRow, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SQLStore struct {
|
type SQLStore struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user