article routes have been moved to support dto
This commit is contained in:
parent
4ab7854ba2
commit
663cbc4e37
215
docs/docs.go
215
docs/docs.go
@ -25,7 +25,14 @@ const docTemplate = `{
|
||||
"Articles"
|
||||
],
|
||||
"summary": "Lists the top 50 records",
|
||||
"responses": {}
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/routes.ArticlesListResults"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/articles/by/sourceid": {
|
||||
@ -46,28 +53,14 @@ const docTemplate = `{
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/articles/by/tag": {
|
||||
"get": {
|
||||
"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": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/routes.ArticlesListResults"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/articles/{ID}": {
|
||||
@ -83,12 +76,47 @@ const docTemplate = `{
|
||||
{
|
||||
"type": "string",
|
||||
"description": "uuid",
|
||||
"name": "id",
|
||||
"name": "ID",
|
||||
"in": "path",
|
||||
"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": {
|
||||
@ -767,6 +795,100 @@ const docTemplate = `{
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"type": "object",
|
||||
"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": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -16,7 +16,14 @@
|
||||
"Articles"
|
||||
],
|
||||
"summary": "Lists the top 50 records",
|
||||
"responses": {}
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/routes.ArticlesListResults"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/articles/by/sourceid": {
|
||||
@ -37,28 +44,14 @@
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/articles/by/tag": {
|
||||
"get": {
|
||||
"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": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/routes.ArticlesListResults"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/articles/{ID}": {
|
||||
@ -74,12 +67,47 @@
|
||||
{
|
||||
"type": "string",
|
||||
"description": "uuid",
|
||||
"name": "id",
|
||||
"name": "ID",
|
||||
"in": "path",
|
||||
"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": {
|
||||
@ -758,6 +786,100 @@
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"type": "object",
|
||||
"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": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -1,5 +1,67 @@
|
||||
basePath: /api
|
||||
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:
|
||||
properties:
|
||||
articleId:
|
||||
@ -70,6 +132,35 @@ definitions:
|
||||
status:
|
||||
type: integer
|
||||
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:
|
||||
properties:
|
||||
message:
|
||||
@ -132,7 +223,11 @@ paths:
|
||||
get:
|
||||
produces:
|
||||
- application/json
|
||||
responses: {}
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/routes.ArticlesListResults'
|
||||
summary: Lists the top 50 records
|
||||
tags:
|
||||
- Articles
|
||||
@ -141,15 +236,37 @@ paths:
|
||||
parameters:
|
||||
- description: uuid
|
||||
in: path
|
||||
name: id
|
||||
name: ID
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses: {}
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/routes.ArticleGetResults'
|
||||
summary: Returns an article based on defined ID.
|
||||
tags:
|
||||
- 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:
|
||||
get:
|
||||
parameters:
|
||||
@ -160,22 +277,11 @@ paths:
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses: {}
|
||||
summary: Finds the articles based on the SourceID provided. Returns the top
|
||||
50.
|
||||
tags:
|
||||
- Articles
|
||||
/articles/by/tag:
|
||||
get:
|
||||
parameters:
|
||||
- description: Tag name
|
||||
in: query
|
||||
name: tag
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses: {}
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/routes.ArticlesListResults'
|
||||
summary: Finds the articles based on the SourceID provided. Returns the top
|
||||
50.
|
||||
tags:
|
||||
|
@ -2,12 +2,45 @@ package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"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 {
|
||||
ID uuid.UUID `json:"ID"`
|
||||
Url string `json:"url"`
|
||||
|
115
dto/articles.go
Normal file
115
dto/articles.go
Normal 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
26
dto/sources.go
Normal 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
13
main.go
@ -2,9 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/jtom38/newsbot/collector/database"
|
||||
"github.com/jtom38/newsbot/collector/docs"
|
||||
"github.com/jtom38/newsbot/collector/routes"
|
||||
"github.com/jtom38/newsbot/collector/services/config"
|
||||
@ -20,16 +22,23 @@ func main() {
|
||||
docs.SwaggerInfo.Host = fmt.Sprintf("%v:8081", address)
|
||||
|
||||
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.Start()
|
||||
|
||||
server := routes.NewServer(ctx)
|
||||
server := routes.NewServer(ctx, queries)
|
||||
|
||||
fmt.Println("API is online and waiting for requests.")
|
||||
fmt.Printf("API: http://%v:8081/api\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 {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -6,61 +6,156 @@ import (
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"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
|
||||
// @Summary Lists the top 50 records
|
||||
// @Produce application/json
|
||||
// @Tags Articles
|
||||
// @Router /articles [get]
|
||||
// @Success 200 {object} ArticlesListResults "OK"
|
||||
func (s *Server) listArticles(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", ApplicationJson)
|
||||
|
||||
res, err := s.Db.ListArticlesByDate(*s.ctx, 50)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
panic(err)
|
||||
p := ArticlesListResults{
|
||||
ApiStatusModel: ApiStatusModel{
|
||||
Message: "OK",
|
||||
StatusCode: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
bres, err := json.Marshal(res)
|
||||
w.Header().Set(HeaderContentType, ApplicationJson)
|
||||
|
||||
res, err := s.dto.ListArticles(r.Context(), 50)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
panic(err)
|
||||
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)
|
||||
}
|
||||
|
||||
// GetArticleById
|
||||
type ArticleGetResults struct {
|
||||
ApiStatusModel
|
||||
Payload models.ArticleDto `json:"payload"`
|
||||
}
|
||||
|
||||
// GetArticle
|
||||
// @Summary Returns an article based on defined ID.
|
||||
// @Param id path string true "uuid"
|
||||
// @Param ID path string true "uuid"
|
||||
// @Produce application/json
|
||||
// @Tags Articles
|
||||
// @Router /articles/{ID} [get]
|
||||
func (s *Server) getArticleById(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
// @Success 200 {object} ArticleGetResults "OK"
|
||||
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")
|
||||
uuid, err := uuid.Parse(id)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
panic(err)
|
||||
s.WriteError(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := s.Db.GetArticleByID(*s.ctx, uuid)
|
||||
res, err := s.dto.GetArticle(r.Context(), uuid)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
panic(err)
|
||||
s.WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
bres, err := json.Marshal(res)
|
||||
p.Payload = res
|
||||
|
||||
bres, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
panic(err)
|
||||
s.WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
// GetArticlesBySourceID
|
||||
// @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
|
||||
// @Tags Articles
|
||||
// @Router /articles/by/sourceid [get]
|
||||
// @Success 200 {object} ArticlesListResults "OK"
|
||||
func (s *Server) GetArticlesBySourceId(w http.ResponseWriter, r *http.Request) {
|
||||
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)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
panic(err)
|
||||
s.WriteError(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := s.Db.GetNewArticlesBySourceId(*s.ctx, uuid)
|
||||
//res, err := s.Db.GetArticlesBySourceId(*s.ctx, uuid)
|
||||
res, err := s.dto.GetArticlesBySourceId(r.Context(), uuid)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
panic(err)
|
||||
s.WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
bres, err := json.Marshal(res)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
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)
|
||||
s.WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(bres)
|
||||
|
@ -6,20 +6,20 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
//"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
_ "github.com/lib/pq"
|
||||
httpSwagger "github.com/swaggo/http-swagger"
|
||||
|
||||
"github.com/jtom38/newsbot/collector/database"
|
||||
"github.com/jtom38/newsbot/collector/dto"
|
||||
"github.com/jtom38/newsbot/collector/services/config"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Router *chi.Mux
|
||||
Db *database.Queries
|
||||
dto dto.DtoClient
|
||||
ctx *context.Context
|
||||
}
|
||||
|
||||
@ -36,16 +36,18 @@ var (
|
||||
ErrUnableToConvertToJson string = "Unable to convert to json"
|
||||
)
|
||||
|
||||
func NewServer(ctx context.Context) *Server {
|
||||
func NewServer(ctx context.Context, db *database.Queries) *Server {
|
||||
s := &Server{
|
||||
ctx: &ctx,
|
||||
Db: db,
|
||||
dto: dto.NewDtoClient(db),
|
||||
}
|
||||
|
||||
db, err := openDatabase(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.Db = db
|
||||
//db, err := openDatabase(ctx)
|
||||
//if err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
//s.Db = db
|
||||
|
||||
s.Router = chi.NewRouter()
|
||||
s.MountMiddleware()
|
||||
@ -76,14 +78,7 @@ func (s *Server) MountRoutes() {
|
||||
httpSwagger.URL("doc.json"), //The url pointing to API definition
|
||||
))
|
||||
|
||||
/* Article Routes */
|
||||
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/articles", s.GetArticleRouter())
|
||||
s.Router.Mount("/api/queue", s.GetQueueRouter())
|
||||
|
||||
/* Discord WebHooks */
|
||||
|
Loading…
Reference in New Issue
Block a user