article routes have been moved to support dto

This commit is contained in:
James Tombleson 2023-01-21 16:08:12 -08:00
parent 4ab7854ba2
commit 663cbc4e37
9 changed files with 827 additions and 149 deletions

View File

@ -25,7 +25,14 @@ const docTemplate = `{
"Articles" "Articles"
], ],
"summary": "Lists the top 50 records", "summary": "Lists the top 50 records",
"responses": {} "responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/routes.ArticlesListResults"
}
}
}
} }
}, },
"/articles/by/sourceid": { "/articles/by/sourceid": {
@ -46,28 +53,14 @@ const docTemplate = `{
"required": true "required": true
} }
], ],
"responses": {} "responses": {
} "200": {
}, "description": "OK",
"/articles/by/tag": { "schema": {
"get": { "$ref": "#/definitions/routes.ArticlesListResults"
"produces": [ }
"application/json"
],
"tags": [
"Articles"
],
"summary": "Finds the articles based on the SourceID provided. Returns the top 50.",
"parameters": [
{
"type": "string",
"description": "Tag name",
"name": "tag",
"in": "query",
"required": true
} }
], }
"responses": {}
} }
}, },
"/articles/{ID}": { "/articles/{ID}": {
@ -83,12 +76,47 @@ const docTemplate = `{
{ {
"type": "string", "type": "string",
"description": "uuid", "description": "uuid",
"name": "id", "name": "ID",
"in": "path", "in": "path",
"required": true "required": true
} }
], ],
"responses": {} "responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/routes.ArticleGetResults"
}
}
}
}
},
"/articles/{ID}/details": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Articles"
],
"summary": "Returns an article and source based on defined ID.",
"parameters": [
{
"type": "string",
"description": "uuid",
"name": "ID",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/routes.ArticleDetailsResult"
}
}
}
} }
}, },
"/discord/webhooks": { "/discord/webhooks": {
@ -767,6 +795,100 @@ const docTemplate = `{
} }
}, },
"definitions": { "definitions": {
"models.ArticleDetailsDto": {
"type": "object",
"properties": {
"authorImage": {
"type": "string"
},
"authorName": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"pubdate": {
"type": "string"
},
"source": {
"$ref": "#/definitions/models.SourceDto"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"thumbnail": {
"type": "string"
},
"title": {
"type": "string"
},
"url": {
"type": "string"
},
"video": {
"type": "string"
},
"videoHeight": {
"type": "integer"
},
"videoWidth": {
"type": "integer"
}
}
},
"models.ArticleDto": {
"type": "object",
"properties": {
"authorImage": {
"type": "string"
},
"authorName": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"pubdate": {
"type": "string"
},
"sourceid": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"thumbnail": {
"type": "string"
},
"title": {
"type": "string"
},
"url": {
"type": "string"
},
"video": {
"type": "string"
},
"videoHeight": {
"type": "integer"
},
"videoWidth": {
"type": "integer"
}
}
},
"models.DiscordQueueDto": { "models.DiscordQueueDto": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -875,6 +997,51 @@ const docTemplate = `{
} }
} }
}, },
"routes.ArticleDetailsResult": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"payload": {
"$ref": "#/definitions/models.ArticleDetailsDto"
},
"status": {
"type": "integer"
}
}
},
"routes.ArticleGetResults": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"payload": {
"$ref": "#/definitions/models.ArticleDto"
},
"status": {
"type": "integer"
}
}
},
"routes.ArticlesListResults": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"payload": {
"type": "array",
"items": {
"$ref": "#/definitions/models.ArticleDto"
}
},
"status": {
"type": "integer"
}
}
},
"routes.GetSourceResult": { "routes.GetSourceResult": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -16,7 +16,14 @@
"Articles" "Articles"
], ],
"summary": "Lists the top 50 records", "summary": "Lists the top 50 records",
"responses": {} "responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/routes.ArticlesListResults"
}
}
}
} }
}, },
"/articles/by/sourceid": { "/articles/by/sourceid": {
@ -37,28 +44,14 @@
"required": true "required": true
} }
], ],
"responses": {} "responses": {
} "200": {
}, "description": "OK",
"/articles/by/tag": { "schema": {
"get": { "$ref": "#/definitions/routes.ArticlesListResults"
"produces": [ }
"application/json"
],
"tags": [
"Articles"
],
"summary": "Finds the articles based on the SourceID provided. Returns the top 50.",
"parameters": [
{
"type": "string",
"description": "Tag name",
"name": "tag",
"in": "query",
"required": true
} }
], }
"responses": {}
} }
}, },
"/articles/{ID}": { "/articles/{ID}": {
@ -74,12 +67,47 @@
{ {
"type": "string", "type": "string",
"description": "uuid", "description": "uuid",
"name": "id", "name": "ID",
"in": "path", "in": "path",
"required": true "required": true
} }
], ],
"responses": {} "responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/routes.ArticleGetResults"
}
}
}
}
},
"/articles/{ID}/details": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Articles"
],
"summary": "Returns an article and source based on defined ID.",
"parameters": [
{
"type": "string",
"description": "uuid",
"name": "ID",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/routes.ArticleDetailsResult"
}
}
}
} }
}, },
"/discord/webhooks": { "/discord/webhooks": {
@ -758,6 +786,100 @@
} }
}, },
"definitions": { "definitions": {
"models.ArticleDetailsDto": {
"type": "object",
"properties": {
"authorImage": {
"type": "string"
},
"authorName": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"pubdate": {
"type": "string"
},
"source": {
"$ref": "#/definitions/models.SourceDto"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"thumbnail": {
"type": "string"
},
"title": {
"type": "string"
},
"url": {
"type": "string"
},
"video": {
"type": "string"
},
"videoHeight": {
"type": "integer"
},
"videoWidth": {
"type": "integer"
}
}
},
"models.ArticleDto": {
"type": "object",
"properties": {
"authorImage": {
"type": "string"
},
"authorName": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"pubdate": {
"type": "string"
},
"sourceid": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"thumbnail": {
"type": "string"
},
"title": {
"type": "string"
},
"url": {
"type": "string"
},
"video": {
"type": "string"
},
"videoHeight": {
"type": "integer"
},
"videoWidth": {
"type": "integer"
}
}
},
"models.DiscordQueueDto": { "models.DiscordQueueDto": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -866,6 +988,51 @@
} }
} }
}, },
"routes.ArticleDetailsResult": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"payload": {
"$ref": "#/definitions/models.ArticleDetailsDto"
},
"status": {
"type": "integer"
}
}
},
"routes.ArticleGetResults": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"payload": {
"$ref": "#/definitions/models.ArticleDto"
},
"status": {
"type": "integer"
}
}
},
"routes.ArticlesListResults": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"payload": {
"type": "array",
"items": {
"$ref": "#/definitions/models.ArticleDto"
}
},
"status": {
"type": "integer"
}
}
},
"routes.GetSourceResult": { "routes.GetSourceResult": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -1,5 +1,67 @@
basePath: /api basePath: /api
definitions: definitions:
models.ArticleDetailsDto:
properties:
authorImage:
type: string
authorName:
type: string
description:
type: string
id:
type: string
pubdate:
type: string
source:
$ref: '#/definitions/models.SourceDto'
tags:
items:
type: string
type: array
thumbnail:
type: string
title:
type: string
url:
type: string
video:
type: string
videoHeight:
type: integer
videoWidth:
type: integer
type: object
models.ArticleDto:
properties:
authorImage:
type: string
authorName:
type: string
description:
type: string
id:
type: string
pubdate:
type: string
sourceid:
type: string
tags:
items:
type: string
type: array
thumbnail:
type: string
title:
type: string
url:
type: string
video:
type: string
videoHeight:
type: integer
videoWidth:
type: integer
type: object
models.DiscordQueueDto: models.DiscordQueueDto:
properties: properties:
articleId: articleId:
@ -70,6 +132,35 @@ definitions:
status: status:
type: integer type: integer
type: object type: object
routes.ArticleDetailsResult:
properties:
message:
type: string
payload:
$ref: '#/definitions/models.ArticleDetailsDto'
status:
type: integer
type: object
routes.ArticleGetResults:
properties:
message:
type: string
payload:
$ref: '#/definitions/models.ArticleDto'
status:
type: integer
type: object
routes.ArticlesListResults:
properties:
message:
type: string
payload:
items:
$ref: '#/definitions/models.ArticleDto'
type: array
status:
type: integer
type: object
routes.GetSourceResult: routes.GetSourceResult:
properties: properties:
message: message:
@ -132,7 +223,11 @@ paths:
get: get:
produces: produces:
- application/json - application/json
responses: {} responses:
"200":
description: OK
schema:
$ref: '#/definitions/routes.ArticlesListResults'
summary: Lists the top 50 records summary: Lists the top 50 records
tags: tags:
- Articles - Articles
@ -141,15 +236,37 @@ paths:
parameters: parameters:
- description: uuid - description: uuid
in: path in: path
name: id name: ID
required: true required: true
type: string type: string
produces: produces:
- application/json - application/json
responses: {} responses:
"200":
description: OK
schema:
$ref: '#/definitions/routes.ArticleGetResults'
summary: Returns an article based on defined ID. summary: Returns an article based on defined ID.
tags: tags:
- Articles - Articles
/articles/{ID}/details:
get:
parameters:
- description: uuid
in: path
name: ID
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/routes.ArticleDetailsResult'
summary: Returns an article and source based on defined ID.
tags:
- Articles
/articles/by/sourceid: /articles/by/sourceid:
get: get:
parameters: parameters:
@ -160,22 +277,11 @@ paths:
type: string type: string
produces: produces:
- application/json - application/json
responses: {} responses:
summary: Finds the articles based on the SourceID provided. Returns the top "200":
50. description: OK
tags: schema:
- Articles $ref: '#/definitions/routes.ArticlesListResults'
/articles/by/tag:
get:
parameters:
- description: Tag name
in: query
name: tag
required: true
type: string
produces:
- application/json
responses: {}
summary: Finds the articles based on the SourceID provided. Returns the top summary: Finds the articles based on the SourceID provided. Returns the top
50. 50.
tags: tags:

View File

@ -2,12 +2,45 @@ package models
import ( import (
"strings" "strings"
"time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jtom38/newsbot/collector/database" "github.com/jtom38/newsbot/collector/database"
) )
type ArticleDto struct {
ID uuid.UUID `json:"id"`
Source uuid.UUID `json:"sourceid"`
Tags []string `json:"tags"`
Title string `json:"title"`
Url string `json:"url"`
Pubdate time.Time `json:"pubdate"`
Video string `json:"video"`
Videoheight int32 `json:"videoHeight"`
Videowidth int32 `json:"videoWidth"`
Thumbnail string `json:"thumbnail"`
Description string `json:"description"`
Authorname string `json:"authorName"`
Authorimage string `json:"authorImage"`
}
type ArticleDetailsDto struct {
ID uuid.UUID `json:"id"`
Source SourceDto `json:"source"`
Tags []string `json:"tags"`
Title string `json:"title"`
Url string `json:"url"`
Pubdate time.Time `json:"pubdate"`
Video string `json:"video"`
Videoheight int32 `json:"videoHeight"`
Videowidth int32 `json:"videoWidth"`
Thumbnail string `json:"thumbnail"`
Description string `json:"description"`
Authorname string `json:"authorName"`
Authorimage string `json:"authorImage"`
}
type DiscordWebHooksDto struct { type DiscordWebHooksDto struct {
ID uuid.UUID `json:"ID"` ID uuid.UUID `json:"ID"`
Url string `json:"url"` Url string `json:"url"`

115
dto/articles.go Normal file
View File

@ -0,0 +1,115 @@
// The converter package lives between the database calls and the API calls.
// This way if any new methods like RPC calls are added later, the API does not need to be reworked as much
package dto
import (
"context"
"strings"
"github.com/google/uuid"
"github.com/jtom38/newsbot/collector/database"
"github.com/jtom38/newsbot/collector/domain/models"
)
type DtoClient struct {
db *database.Queries
}
func NewDtoClient(db *database.Queries) DtoClient {
return DtoClient{
db: db,
}
}
func (c DtoClient) ListArticles(ctx context.Context, limit int) ([]models.ArticleDto, error) {
var res []models.ArticleDto
a, err := c.db.ListArticles(ctx, int32(limit))
if err != nil {
return res, err
}
for _, article := range a {
res = append(res, c.convertArticle(article))
}
return res, nil
}
func (c DtoClient) GetArticle(ctx context.Context, ID uuid.UUID) (models.ArticleDto, error) {
a, err := c.db.GetArticleByID(ctx, ID)
if err != nil {
return models.ArticleDto{}, err
}
return c.convertArticle(a), nil
}
func (c DtoClient) GetArticleDetails(ctx context.Context, ID uuid.UUID) (models.ArticleDetailsDto, error) {
a, err := c.db.GetArticleByID(ctx, ID)
if err != nil {
return models.ArticleDetailsDto{}, err
}
s, err := c.db.GetSourceByID(ctx, a.Sourceid)
if err != nil {
return models.ArticleDetailsDto{}, err
}
res := c.convertArticleDetails(a, s)
return res, nil
}
func (c DtoClient) GetArticlesBySourceId(ctx context.Context, SourceID uuid.UUID) ([]models.ArticleDto, error) {
var res []models.ArticleDto
a, err := c.db.GetArticlesBySourceId(ctx, SourceID)
if err != nil {
return res, err
}
for _, article := range a {
res = append(res, c.convertArticle(article))
}
return res, nil
}
func (c DtoClient) convertArticle(i database.Article) models.ArticleDto {
return models.ArticleDto{
ID: i.ID,
Source: i.Sourceid,
Tags: c.SplitTags(i.Tags),
Title: i.Title,
Url: i.Url,
Pubdate: i.Pubdate,
Video: i.Video.String,
Videoheight: i.Videoheight,
Videowidth: i.Videoheight,
Thumbnail: i.Thumbnail,
Description: i.Description,
Authorname: i.Authorname.String,
Authorimage: i.Authorimage.String,
}
}
func (c DtoClient) convertArticleDetails(i database.Article, s database.Source) models.ArticleDetailsDto {
return models.ArticleDetailsDto{
ID: i.ID,
Source: c.ConvertToSourceDto(s),
Tags: c.SplitTags(i.Tags),
Title: i.Title,
Url: i.Url,
Pubdate: i.Pubdate,
Video: i.Video.String,
Videoheight: i.Videoheight,
Videowidth: i.Videoheight,
Thumbnail: i.Thumbnail,
Description: i.Description,
Authorname: i.Authorname.String,
Authorimage: i.Authorimage.String,
}
}
func (c DtoClient) SplitTags(t string) []string {
return strings.Split(t, ", ")
}

26
dto/sources.go Normal file
View File

@ -0,0 +1,26 @@
package dto
import (
"github.com/jtom38/newsbot/collector/database"
"github.com/jtom38/newsbot/collector/domain/models"
)
func (c DtoClient) ConvertToSourceDto(i database.Source) models.SourceDto {
var deleted bool
if !i.Deleted.Valid {
deleted = true
}
return models.SourceDto{
ID: i.ID,
Site: i.Site,
Name: i.Name,
Source: i.Source,
Type: i.Type,
Value: i.Value.String,
Enabled: i.Enabled,
Url: i.Url,
Tags: c.SplitTags(i.Tags),
Deleted: deleted,
}
}

13
main.go
View File

@ -2,9 +2,11 @@ package main
import ( import (
"context" "context"
"database/sql"
"fmt" "fmt"
"net/http" "net/http"
"github.com/jtom38/newsbot/collector/database"
"github.com/jtom38/newsbot/collector/docs" "github.com/jtom38/newsbot/collector/docs"
"github.com/jtom38/newsbot/collector/routes" "github.com/jtom38/newsbot/collector/routes"
"github.com/jtom38/newsbot/collector/services/config" "github.com/jtom38/newsbot/collector/services/config"
@ -20,16 +22,23 @@ func main() {
docs.SwaggerInfo.Host = fmt.Sprintf("%v:8081", address) docs.SwaggerInfo.Host = fmt.Sprintf("%v:8081", address)
ctx := context.Background() ctx := context.Background()
db, err := sql.Open("postgres", cfg.GetConfig(config.Sql_Connection_String))
if err != nil {
panic(err)
}
queries := database.New(db)
c := cron.New(ctx) c := cron.New(ctx)
c.Start() c.Start()
server := routes.NewServer(ctx) server := routes.NewServer(ctx, queries)
fmt.Println("API is online and waiting for requests.") fmt.Println("API is online and waiting for requests.")
fmt.Printf("API: http://%v:8081/api\r\n", address) fmt.Printf("API: http://%v:8081/api\r\n", address)
fmt.Printf("Swagger: http://%v:8081/swagger/index.html\r\n", address) fmt.Printf("Swagger: http://%v:8081/swagger/index.html\r\n", address)
err := http.ListenAndServe(":8081", server.Router) err = http.ListenAndServe(":8081", server.Router)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -6,61 +6,156 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jtom38/newsbot/collector/domain/models"
) )
func (s *Server) GetArticleRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", s.listArticles)
r.Route("/{ID}", func(r chi.Router) {
r.Get("/", s.getArticle)
r.Get("/details", s.getArticleDetails)
})
r.Get("/by/sourceid", s.GetArticlesBySourceId)
return r
}
type ArticlesListResults struct {
ApiStatusModel
Payload []models.ArticleDto `json:"payload"`
}
// ListArticles // ListArticles
// @Summary Lists the top 50 records // @Summary Lists the top 50 records
// @Produce application/json // @Produce application/json
// @Tags Articles // @Tags Articles
// @Router /articles [get] // @Router /articles [get]
// @Success 200 {object} ArticlesListResults "OK"
func (s *Server) listArticles(w http.ResponseWriter, r *http.Request) { func (s *Server) listArticles(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", ApplicationJson) p := ArticlesListResults{
ApiStatusModel: ApiStatusModel{
res, err := s.Db.ListArticlesByDate(*s.ctx, 50) Message: "OK",
if err != nil { StatusCode: http.StatusOK,
w.Write([]byte(err.Error())) },
panic(err)
} }
bres, err := json.Marshal(res) w.Header().Set(HeaderContentType, ApplicationJson)
res, err := s.dto.ListArticles(r.Context(), 50)
if err != nil { if err != nil {
w.Write([]byte(err.Error())) s.WriteError(w, err.Error(), http.StatusInternalServerError)
panic(err) return
}
p.Payload = res
bres, err := json.Marshal(p)
if err != nil {
s.WriteError(w, err.Error(), http.StatusInternalServerError)
return
} }
w.Write(bres) w.Write(bres)
} }
// GetArticleById type ArticleGetResults struct {
ApiStatusModel
Payload models.ArticleDto `json:"payload"`
}
// GetArticle
// @Summary Returns an article based on defined ID. // @Summary Returns an article based on defined ID.
// @Param id path string true "uuid" // @Param ID path string true "uuid"
// @Produce application/json // @Produce application/json
// @Tags Articles // @Tags Articles
// @Router /articles/{ID} [get] // @Router /articles/{ID} [get]
func (s *Server) getArticleById(w http.ResponseWriter, r *http.Request) { // @Success 200 {object} ArticleGetResults "OK"
w.Header().Set("Content-Type", "application/json") func (s *Server) getArticle(w http.ResponseWriter, r *http.Request) {
p := ArticleGetResults {
ApiStatusModel: ApiStatusModel{
Message: "OK",
StatusCode: http.StatusOK,
},
}
w.Header().Set(HeaderContentType, ApplicationJson)
id := chi.URLParam(r, "ID") id := chi.URLParam(r, "ID")
uuid, err := uuid.Parse(id) uuid, err := uuid.Parse(id)
if err != nil { if err != nil {
w.Write([]byte(err.Error())) s.WriteError(w, err.Error(), http.StatusBadRequest)
panic(err) return
} }
res, err := s.Db.GetArticleByID(*s.ctx, uuid) res, err := s.dto.GetArticle(r.Context(), uuid)
if err != nil { if err != nil {
w.Write([]byte(err.Error())) s.WriteError(w, err.Error(), http.StatusInternalServerError)
panic(err) return
} }
bres, err := json.Marshal(res) p.Payload = res
bres, err := json.Marshal(p)
if err != nil { if err != nil {
w.Write([]byte(err.Error())) s.WriteError(w, err.Error(), http.StatusInternalServerError)
panic(err) return
} }
w.Write(bres) w.Write(bres)
} }
type ArticleDetailsResult struct {
ApiStatusModel
Payload models.ArticleDetailsDto `json:"payload"`
}
// GetArticleDetails
// @Summary Returns an article and source based on defined ID.
// @Param ID path string true "uuid"
// @Produce application/json
// @Tags Articles
// @Router /articles/{ID}/details [get]
// @Success 200 {object} ArticleDetailsResult "OK"
func (s *Server) getArticleDetails(w http.ResponseWriter, r *http.Request) {
p := ArticleDetailsResult {
ApiStatusModel: ApiStatusModel{
Message: "OK",
StatusCode: http.StatusOK,
},
}
w.Header().Set(HeaderContentType, ApplicationJson)
id := chi.URLParam(r, "ID")
uuid, err := uuid.Parse(id)
if err != nil {
s.WriteError(w, err.Error(), http.StatusBadRequest)
return
}
res, err := s.dto.GetArticleDetails(r.Context(), uuid)
if err != nil {
s.WriteError(w, err.Error(), http.StatusInternalServerError)
return
}
p.Payload = res
bres, err := json.Marshal(p)
if err != nil {
s.WriteError(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(bres)
}
type ArticlesBySourceIDResults struct {
ApiStatusModel
Payload []models.ArticleDto `json:"payload"`
}
// TODO add page support // TODO add page support
// GetArticlesBySourceID // GetArticlesBySourceID
// @Summary Finds the articles based on the SourceID provided. Returns the top 50. // @Summary Finds the articles based on the SourceID provided. Returns the top 50.
@ -68,6 +163,7 @@ func (s *Server) getArticleById(w http.ResponseWriter, r *http.Request) {
// @Produce application/json // @Produce application/json
// @Tags Articles // @Tags Articles
// @Router /articles/by/sourceid [get] // @Router /articles/by/sourceid [get]
// @Success 200 {object} ArticlesListResults "OK"
func (s *Server) GetArticlesBySourceId(w http.ResponseWriter, r *http.Request) { func (s *Server) GetArticlesBySourceId(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@ -77,56 +173,20 @@ func (s *Server) GetArticlesBySourceId(w http.ResponseWriter, r *http.Request) {
uuid, err := uuid.Parse(_id) uuid, err := uuid.Parse(_id)
if err != nil { if err != nil {
w.Write([]byte(err.Error())) s.WriteError(w, err.Error(), http.StatusBadRequest)
panic(err) return
} }
res, err := s.Db.GetNewArticlesBySourceId(*s.ctx, uuid) res, err := s.dto.GetArticlesBySourceId(r.Context(), uuid)
//res, err := s.Db.GetArticlesBySourceId(*s.ctx, uuid)
if err != nil { if err != nil {
w.Write([]byte(err.Error())) s.WriteError(w, err.Error(), http.StatusInternalServerError)
panic(err) return
} }
bres, err := json.Marshal(res) bres, err := json.Marshal(res)
if err != nil { if err != nil {
w.Write([]byte(err.Error())) s.WriteError(w, err.Error(), http.StatusInternalServerError)
panic(err) return
}
w.Write(bres)
}
// TODO add page support
// GetArticlesByTag
// @Summary Finds the articles based on the SourceID provided. Returns the top 50.
// @Param tag query string true "Tag name"
// @Produce application/json
// @Tags Articles
// @Router /articles/by/tag [get]
func (s *Server) GetArticlesByTag(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
r.URL.Query()
query := r.URL.Query()
_id := query["tag"][0]
uuid, err := uuid.Parse(_id)
if err != nil {
w.Write([]byte(err.Error()))
panic(err)
}
res, err := s.Db.GetArticlesBySourceId(*s.ctx, uuid)
if err != nil {
w.Write([]byte(err.Error()))
panic(err)
}
bres, err := json.Marshal(res)
if err != nil {
w.Write([]byte(err.Error()))
panic(err)
} }
w.Write(bres) w.Write(bres)

View File

@ -6,20 +6,20 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
//"net/http"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware" "github.com/go-chi/chi/v5/middleware"
_ "github.com/lib/pq" _ "github.com/lib/pq"
httpSwagger "github.com/swaggo/http-swagger" httpSwagger "github.com/swaggo/http-swagger"
"github.com/jtom38/newsbot/collector/database" "github.com/jtom38/newsbot/collector/database"
"github.com/jtom38/newsbot/collector/dto"
"github.com/jtom38/newsbot/collector/services/config" "github.com/jtom38/newsbot/collector/services/config"
) )
type Server struct { type Server struct {
Router *chi.Mux Router *chi.Mux
Db *database.Queries Db *database.Queries
dto dto.DtoClient
ctx *context.Context ctx *context.Context
} }
@ -36,16 +36,18 @@ var (
ErrUnableToConvertToJson string = "Unable to convert to json" ErrUnableToConvertToJson string = "Unable to convert to json"
) )
func NewServer(ctx context.Context) *Server { func NewServer(ctx context.Context, db *database.Queries) *Server {
s := &Server{ s := &Server{
ctx: &ctx, ctx: &ctx,
Db: db,
dto: dto.NewDtoClient(db),
} }
db, err := openDatabase(ctx) //db, err := openDatabase(ctx)
if err != nil { //if err != nil {
panic(err) // panic(err)
} //}
s.Db = db //s.Db = db
s.Router = chi.NewRouter() s.Router = chi.NewRouter()
s.MountMiddleware() s.MountMiddleware()
@ -76,14 +78,7 @@ func (s *Server) MountRoutes() {
httpSwagger.URL("doc.json"), //The url pointing to API definition httpSwagger.URL("doc.json"), //The url pointing to API definition
)) ))
/* Article Routes */ s.Router.Mount("/api/articles", s.GetArticleRouter())
s.Router.Get("/api/articles", s.listArticles)
s.Router.Route("/api/articles/{ID}", func(r chi.Router) {
r.Get("/", s.getArticleById)
})
s.Router.Get("/api/articles/by/sourceid", s.GetArticlesBySourceId)
/* Queue */
s.Router.Mount("/api/queue", s.GetQueueRouter()) s.Router.Mount("/api/queue", s.GetQueueRouter())
/* Discord WebHooks */ /* Discord WebHooks */