sqlc removed and adding sessionToken to jwt
This commit is contained in:
parent
4e9a17209f
commit
47058dd866
42
docs/docs.go
42
docs/docs.go
@ -996,6 +996,45 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/users/refresh/sessionToken": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Users"
|
||||||
|
],
|
||||||
|
"summary": "Revokes the current session token and replaces it with a new one.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.BaseResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.BaseResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.BaseResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/users/refreshToken": {
|
"/v1/users/refreshToken": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@ -1311,6 +1350,9 @@ const docTemplate = `{
|
|||||||
"refreshToken": {
|
"refreshToken": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"sessionToken": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"token": {
|
"token": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -987,6 +987,45 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/users/refresh/sessionToken": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Users"
|
||||||
|
],
|
||||||
|
"summary": "Revokes the current session token and replaces it with a new one.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.BaseResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.BaseResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.BaseResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/users/refreshToken": {
|
"/v1/users/refreshToken": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@ -1302,6 +1341,9 @@
|
|||||||
"refreshToken": {
|
"refreshToken": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"sessionToken": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"token": {
|
"token": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -84,6 +84,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
refreshToken:
|
refreshToken:
|
||||||
type: string
|
type: string
|
||||||
|
sessionToken:
|
||||||
|
type: string
|
||||||
token:
|
token:
|
||||||
type: string
|
type: string
|
||||||
type:
|
type:
|
||||||
@ -750,6 +752,30 @@ paths:
|
|||||||
summary: Logs into the API and returns a bearer token if successful
|
summary: Logs into the API and returns a bearer token if successful
|
||||||
tags:
|
tags:
|
||||||
- Users
|
- Users
|
||||||
|
/v1/users/refresh/sessionToken:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.BaseResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.BaseResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.BaseResponse'
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Revokes the current session token and replaces it with a new one.
|
||||||
|
tags:
|
||||||
|
- Users
|
||||||
/v1/users/refreshToken:
|
/v1/users/refreshToken:
|
||||||
post:
|
post:
|
||||||
parameters:
|
parameters:
|
||||||
|
@ -10,6 +10,7 @@ type LoginResponse struct {
|
|||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
RefreshToken string `json:"refreshToken"`
|
RefreshToken string `json:"refreshToken"`
|
||||||
|
SessionToken string `json:"sessionToken"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArticleResponse struct {
|
type ArticleResponse struct {
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// sqlc v1.16.0
|
|
||||||
|
|
||||||
package database
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"database/sql"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DBTX interface {
|
|
||||||
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
|
||||||
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
|
||||||
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
|
||||||
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(db DBTX) *Queries {
|
|
||||||
return &Queries{db: db}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Queries struct {
|
|
||||||
db DBTX
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
|
||||||
return &Queries{
|
|
||||||
db: tx,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package database
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SourceDto struct {
|
|
||||||
ID uuid.UUID `json:"id"`
|
|
||||||
Site string `json:"site"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Source string `json:"source"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
Url string `json:"url"`
|
|
||||||
Tags []string `json:"tags"`
|
|
||||||
Deleted bool `json:"deleted"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConvertToSourceDto(i Source) SourceDto {
|
|
||||||
var deleted bool
|
|
||||||
if !i.Deleted.Valid {
|
|
||||||
deleted = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return 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: splitTags(i.Tags),
|
|
||||||
Deleted: deleted,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func splitTags(t string) []string {
|
|
||||||
items := strings.Split(t, ", ")
|
|
||||||
return items
|
|
||||||
}
|
|
@ -0,0 +1,9 @@
|
|||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
ALTER TABLE Users ADD SessionToken TEXT;
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
ALTER TABLE Users DROP SessionToken;
|
||||||
|
-- +goose StatementEnd
|
@ -1,73 +0,0 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// sqlc v1.16.0
|
|
||||||
|
|
||||||
package database
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Article struct {
|
|
||||||
ID uuid.UUID
|
|
||||||
Sourceid uuid.UUID
|
|
||||||
Tags string
|
|
||||||
Title string
|
|
||||||
Url string
|
|
||||||
Pubdate time.Time
|
|
||||||
Video sql.NullString
|
|
||||||
Videoheight int32
|
|
||||||
Videowidth int32
|
|
||||||
Thumbnail string
|
|
||||||
Description string
|
|
||||||
Authorname sql.NullString
|
|
||||||
Authorimage sql.NullString
|
|
||||||
}
|
|
||||||
|
|
||||||
type Discordqueue struct {
|
|
||||||
ID uuid.UUID
|
|
||||||
Articleid uuid.UUID
|
|
||||||
}
|
|
||||||
|
|
||||||
type Discordwebhook struct {
|
|
||||||
ID uuid.UUID
|
|
||||||
Url string
|
|
||||||
Server string
|
|
||||||
Channel string
|
|
||||||
Enabled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type Icon struct {
|
|
||||||
ID uuid.UUID
|
|
||||||
Filename string
|
|
||||||
Site string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Setting struct {
|
|
||||||
ID uuid.UUID
|
|
||||||
Key string
|
|
||||||
Value string
|
|
||||||
Options sql.NullString
|
|
||||||
}
|
|
||||||
|
|
||||||
type Source struct {
|
|
||||||
ID uuid.UUID
|
|
||||||
Site string
|
|
||||||
Name string
|
|
||||||
Source string
|
|
||||||
Type string
|
|
||||||
Value sql.NullString
|
|
||||||
Enabled bool
|
|
||||||
Url string
|
|
||||||
Tags string
|
|
||||||
Deleted sql.NullBool
|
|
||||||
}
|
|
||||||
|
|
||||||
type Subscription struct {
|
|
||||||
ID uuid.UUID
|
|
||||||
Discordwebhookid uuid.UUID
|
|
||||||
Sourceid uuid.UUID
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,215 +0,0 @@
|
|||||||
/* Articles */
|
|
||||||
-- name: GetArticleByID :one
|
|
||||||
Select * from Articles
|
|
||||||
WHERE ID = $1 LIMIT 1;
|
|
||||||
|
|
||||||
-- name: GetArticleByUrl :one
|
|
||||||
Select * from Articles
|
|
||||||
Where Url = $1 LIMIT 1;
|
|
||||||
|
|
||||||
-- name: ListArticles :many
|
|
||||||
Select * From articles
|
|
||||||
Order By PubDate DESC
|
|
||||||
offset $2
|
|
||||||
fetch next $1 rows only;
|
|
||||||
|
|
||||||
-- name: ListArticlesByDate :many
|
|
||||||
Select * From articles
|
|
||||||
ORDER BY pubdate desc
|
|
||||||
Limit $1;
|
|
||||||
|
|
||||||
-- name: GetArticlesBySource :many
|
|
||||||
select * from articles
|
|
||||||
INNER join sources on articles.sourceid=Sources.ID
|
|
||||||
where site = $1;
|
|
||||||
|
|
||||||
-- name: ListNewArticlesBySourceId :many
|
|
||||||
SELECT * FROM articles
|
|
||||||
Where sourceid = $1
|
|
||||||
ORDER BY pubdate desc
|
|
||||||
offset $3
|
|
||||||
fetch next $2 rows only;
|
|
||||||
|
|
||||||
-- name: ListOldestArticlesBySourceId :many
|
|
||||||
SELECT * FROM articles
|
|
||||||
Where sourceid = $1
|
|
||||||
ORDER BY pubdate asc
|
|
||||||
offset $3
|
|
||||||
fetch next $2 rows only;
|
|
||||||
|
|
||||||
|
|
||||||
-- name: ListArticlesBySourceId :many
|
|
||||||
Select * From articles
|
|
||||||
Where sourceid = $1
|
|
||||||
Limit 50;
|
|
||||||
|
|
||||||
-- name: GetArticlesBySourceName :many
|
|
||||||
select
|
|
||||||
articles.ID, articles.SourceId, articles.Tags, articles.Title, articles.Url, articles.PubDate, articles.Video, articles.VideoHeight, articles.VideoWidth, articles.Thumbnail, articles.Description, articles.AuthorName, articles.AuthorImage, sources.source, sources.name
|
|
||||||
From articles
|
|
||||||
Left Join sources
|
|
||||||
On articles.sourceid = sources.id
|
|
||||||
Where name = $1;
|
|
||||||
|
|
||||||
-- name: ListArticlesByPage :many
|
|
||||||
select * from articles
|
|
||||||
order by pubdate desc
|
|
||||||
offset $2
|
|
||||||
fetch next $1 rows only;
|
|
||||||
|
|
||||||
-- name: CreateArticle :exec
|
|
||||||
INSERT INTO Articles
|
|
||||||
(ID, SourceId, Tags, Title, Url, PubDate, Video, VideoHeight, VideoWidth, Thumbnail, Description, AuthorName, AuthorImage)
|
|
||||||
Values
|
|
||||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);
|
|
||||||
|
|
||||||
|
|
||||||
/* DiscordQueue */
|
|
||||||
-- name: CreateDiscordQueue :exec
|
|
||||||
Insert into DiscordQueue
|
|
||||||
(ID, ArticleId)
|
|
||||||
Values
|
|
||||||
($1, $2);
|
|
||||||
|
|
||||||
-- name: GetDiscordQueueByID :one
|
|
||||||
Select * from DiscordQueue
|
|
||||||
Where ID = $1 LIMIT 1;
|
|
||||||
|
|
||||||
-- name: DeleteDiscordQueueItem :exec
|
|
||||||
Delete From DiscordQueue Where ID = $1;
|
|
||||||
|
|
||||||
-- name: ListDiscordQueueItems :many
|
|
||||||
Select * from DiscordQueue LIMIT $1;
|
|
||||||
|
|
||||||
/* DiscordWebHooks */
|
|
||||||
-- name: CreateDiscordWebHook :exec
|
|
||||||
Insert Into DiscordWebHooks
|
|
||||||
(ID, Url, Server, Channel, Enabled)
|
|
||||||
Values
|
|
||||||
($1, $2, $3, $4, $5);
|
|
||||||
|
|
||||||
-- name: GetDiscordWebHooksByID :one
|
|
||||||
Select * from DiscordWebHooks
|
|
||||||
Where ID = $1 LIMIT 1;
|
|
||||||
|
|
||||||
-- name: ListDiscordWebHooksByServer :many
|
|
||||||
Select * From DiscordWebHooks
|
|
||||||
Where Server = $1;
|
|
||||||
|
|
||||||
-- name: GetDiscordWebHooksByServerAndChannel :many
|
|
||||||
SELECT * FROM DiscordWebHooks
|
|
||||||
WHERE Server = $1 and Channel = $2;
|
|
||||||
|
|
||||||
-- name: GetDiscordWebHookByUrl :one
|
|
||||||
Select * From DiscordWebHooks Where url = $1;
|
|
||||||
|
|
||||||
-- name: ListDiscordWebhooks :many
|
|
||||||
Select * From discordwebhooks LIMIT $1;
|
|
||||||
|
|
||||||
-- name: DeleteDiscordWebHooks :exec
|
|
||||||
Delete From discordwebhooks Where ID = $1;
|
|
||||||
|
|
||||||
-- name: DisableDiscordWebHook :exec
|
|
||||||
Update discordwebhooks Set Enabled = FALSE where ID = $1;
|
|
||||||
|
|
||||||
-- name: EnableDiscordWebHook :exec
|
|
||||||
Update discordwebhooks Set Enabled = TRUE where ID = $1;
|
|
||||||
|
|
||||||
/* Icons */
|
|
||||||
|
|
||||||
-- name: CreateIcon :exec
|
|
||||||
INSERT INTO Icons
|
|
||||||
(ID, FileName, Site)
|
|
||||||
VALUES
|
|
||||||
($1,$2,$3);
|
|
||||||
|
|
||||||
-- name: GetIconByID :one
|
|
||||||
Select * FROM Icons
|
|
||||||
Where ID = $1 Limit 1;
|
|
||||||
|
|
||||||
-- name: GetIconBySite :one
|
|
||||||
Select * FROM Icons
|
|
||||||
Where Site = $1 Limit 1;
|
|
||||||
|
|
||||||
-- name: DeleteIcon :exec
|
|
||||||
Delete From Icons where ID = $1;
|
|
||||||
|
|
||||||
/* Settings */
|
|
||||||
|
|
||||||
-- name: CreateSettings :one
|
|
||||||
Insert Into settings
|
|
||||||
(ID, Key, Value, OPTIONS)
|
|
||||||
Values
|
|
||||||
($1,$2,$3,$4)
|
|
||||||
RETURNING *;
|
|
||||||
|
|
||||||
-- name: GetSettingByID :one
|
|
||||||
Select * From settings
|
|
||||||
Where ID = $1 Limit 1;
|
|
||||||
|
|
||||||
-- name: GetSettingByKey :one
|
|
||||||
Select * From settings Where
|
|
||||||
Key = $1 Limit 1;
|
|
||||||
|
|
||||||
-- name: GetSettingByValue :one
|
|
||||||
Select * From settings Where
|
|
||||||
Value = $1 Limit 1;
|
|
||||||
|
|
||||||
-- name: DeleteSetting :exec
|
|
||||||
Delete From settings Where ID = $1;
|
|
||||||
|
|
||||||
/* Sources */
|
|
||||||
|
|
||||||
-- name: CreateSource :exec
|
|
||||||
Insert Into Sources
|
|
||||||
(ID, Site, Name, Source, Type, Value, Enabled, Url, Tags)
|
|
||||||
Values
|
|
||||||
($1,$2,$3,$4,$5,$6,$7,$8,$9);
|
|
||||||
|
|
||||||
-- name: GetSourceByID :one
|
|
||||||
Select * From Sources where ID = $1 Limit 1;
|
|
||||||
|
|
||||||
-- name: GetSourceByName :one
|
|
||||||
Select * from Sources where name = $1 Limit 1;
|
|
||||||
|
|
||||||
-- name: GetSourceByNameAndSource :one
|
|
||||||
Select * from Sources WHERE name = $1 and source = $2;
|
|
||||||
|
|
||||||
-- name: ListSources :many
|
|
||||||
Select * From Sources Limit $1;
|
|
||||||
|
|
||||||
-- name: ListSourcesBySource :many
|
|
||||||
Select * From Sources where Source = $1;
|
|
||||||
|
|
||||||
-- name: DeleteSource :exec
|
|
||||||
UPDATE Sources Set Disabled = TRUE where id = $1;
|
|
||||||
|
|
||||||
-- name: DisableSource :exec
|
|
||||||
Update Sources Set Enabled = FALSE where ID = $1;
|
|
||||||
|
|
||||||
-- name: EnableSource :exec
|
|
||||||
Update Sources Set Enabled = TRUE where ID = $1;
|
|
||||||
|
|
||||||
|
|
||||||
/* Subscriptions */
|
|
||||||
|
|
||||||
-- name: CreateSubscription :exec
|
|
||||||
Insert Into subscriptions (ID, DiscordWebHookId, SourceId) Values ($1, $2, $3);
|
|
||||||
|
|
||||||
-- name: ListSubscriptions :many
|
|
||||||
Select * From subscriptions Limit $1;
|
|
||||||
|
|
||||||
-- name: ListSubscriptionsBySourceId :many
|
|
||||||
Select * From subscriptions where sourceid = $1;
|
|
||||||
|
|
||||||
-- name: QuerySubscriptions :one
|
|
||||||
Select * From subscriptions Where discordwebhookid = $1 and sourceid = $2 Limit 1;
|
|
||||||
|
|
||||||
-- name: GetSubscriptionsBySourceID :many
|
|
||||||
Select * From subscriptions Where sourceid = $1;
|
|
||||||
|
|
||||||
-- name: GetSubscriptionsByDiscordWebHookId :many
|
|
||||||
Select * from subscriptions Where discordwebhookid = $1;
|
|
||||||
|
|
||||||
-- name: DeleteSubscription :exec
|
|
||||||
Delete From subscriptions Where id = $1;
|
|
@ -1,61 +0,0 @@
|
|||||||
CREATE TABLE Articles (
|
|
||||||
ID uuid PRIMARY KEY,
|
|
||||||
SourceId uuid NOT null,
|
|
||||||
Tags TEXT NOT NULL,
|
|
||||||
Title TEXT NOT NULL,
|
|
||||||
Url TEXT NOT NULL,
|
|
||||||
PubDate timestamp NOT NULL,
|
|
||||||
Video TEXT,
|
|
||||||
VideoHeight int NOT NULL,
|
|
||||||
VideoWidth int NOT NULL,
|
|
||||||
Thumbnail TEXT NOT NULL,
|
|
||||||
Description TEXT NOT NULL,
|
|
||||||
AuthorName TEXT,
|
|
||||||
AuthorImage TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE Table DiscordQueue (
|
|
||||||
ID uuid PRIMARY KEY,
|
|
||||||
ArticleId uuid NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE Table DiscordWebHooks (
|
|
||||||
ID uuid PRIMARY KEY,
|
|
||||||
Url TEXT NOT NULL, -- Webhook Url
|
|
||||||
Server TEXT NOT NULL, -- Defines the server its bound it. Used for refrence
|
|
||||||
Channel TEXT NOT NULL, -- Defines the channel its bound to. Used for refrence
|
|
||||||
Enabled BOOLEAN NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE Table Icons (
|
|
||||||
ID uuid PRIMARY Key,
|
|
||||||
FileName TEXT NOT NULL,
|
|
||||||
Site TEXT NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
Create Table Settings (
|
|
||||||
ID uuid PRIMARY Key,
|
|
||||||
Key TEXT NOT NULL,
|
|
||||||
Value TEXT NOT NULL,
|
|
||||||
Options TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
Create Table Sources (
|
|
||||||
ID uuid PRIMARY Key,
|
|
||||||
Site TEXT NOT NULL, -- Vanity name
|
|
||||||
Name TEXT NOT NULL, -- Defines the name of the source. IE: dadjokes
|
|
||||||
Source TEXT NOT NULL, -- Defines the service that will use this reocrd. IE reddit or youtube
|
|
||||||
Type TEXT NOT NULL, -- Defines what kind of feed this is. feed, user, tag
|
|
||||||
Value TEXT,
|
|
||||||
Enabled BOOLEAN NOT NULL,
|
|
||||||
Url TEXT NOT NULL,
|
|
||||||
Tags TEXT NOT NULL,
|
|
||||||
Deleted BOOLEAN
|
|
||||||
);
|
|
||||||
|
|
||||||
/* This table is used to track what the Web Hook wants to have sent by Source */;
|
|
||||||
Create TABLE Subscriptions (
|
|
||||||
ID uuid Primary Key,
|
|
||||||
DiscordWebHookID uuid Not Null,
|
|
||||||
SourceID uuid Not Null
|
|
||||||
);
|
|
@ -128,6 +128,7 @@ type UserEntity struct {
|
|||||||
Username string
|
Username string
|
||||||
Hash string
|
Hash string
|
||||||
Scopes string
|
Scopes string
|
||||||
|
SessionToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
type RefreshTokenEntity struct {
|
type RefreshTokenEntity struct {
|
||||||
|
@ -83,11 +83,11 @@ func (j JwtToken) hasScope(scope string) error {
|
|||||||
return errors.New(ErrJwtScopeMissing)
|
return errors.New(ErrJwtScopeMissing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) generateJwt(username, issuer string, userScopes []string, userId int64) (string, error) {
|
func (h *Handler) generateJwt(username, issuer, sessionToken string, userScopes []string, userId int64) (string, error) {
|
||||||
return h.generateJwtWithExp(username, issuer, userScopes, userId, time.Now().Add(10*time.Minute))
|
return h.generateJwtWithExp(username, issuer, sessionToken, userScopes, userId, time.Now().Add(10*time.Minute))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) generateJwtWithExp(username, issuer string, userScopes []string, userId int64, expiresAt time.Time) (string, error) {
|
func (h *Handler) generateJwtWithExp(username, issuer, sessionToken string, userScopes []string, userId int64, expiresAt time.Time) (string, error) {
|
||||||
secret := []byte(h.config.JwtSecret)
|
secret := []byte(h.config.JwtSecret)
|
||||||
|
|
||||||
// Anyone who wants to decrypt the key needs to use the same method
|
// Anyone who wants to decrypt the key needs to use the same method
|
||||||
@ -98,6 +98,7 @@ func (h *Handler) generateJwtWithExp(username, issuer string, userScopes []strin
|
|||||||
claims["username"] = username
|
claims["username"] = username
|
||||||
claims["iss"] = issuer
|
claims["iss"] = issuer
|
||||||
claims["userId"] = userId
|
claims["userId"] = userId
|
||||||
|
claims["sessionToken"] = sessionToken
|
||||||
|
|
||||||
var scopes []string
|
var scopes []string
|
||||||
scopes = append(scopes, userScopes...)
|
scopes = append(scopes, userScopes...)
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"git.jamestombleson.com/jtom38/newsbot-api/domain"
|
"git.jamestombleson.com/jtom38/newsbot-api/domain"
|
||||||
"git.jamestombleson.com/jtom38/newsbot-api/internal/repository"
|
"git.jamestombleson.com/jtom38/newsbot-api/internal/repository"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ func (h *Handler) AuthRegister(c echo.Context) error {
|
|||||||
return h.WriteError(c, err, http.StatusInternalServerError)
|
return h.WriteError(c, err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = h.repo.Users.Create(c.Request().Context(), username, password, domain.ScopeArticleRead)
|
_, err = h.repo.Users.Create(c.Request().Context(), username, password, "", domain.ScopeArticleRead)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return h.InternalServerErrorResponse(c, err.Error())
|
return h.InternalServerErrorResponse(c, err.Error())
|
||||||
}
|
}
|
||||||
@ -91,8 +92,12 @@ func (h *Handler) AuthLogin(c echo.Context) error {
|
|||||||
// TODO think about moving this down some?
|
// TODO think about moving this down some?
|
||||||
expiresAt := time.Now().Add(time.Hour * 48)
|
expiresAt := time.Now().Add(time.Hour * 48)
|
||||||
userScopes := strings.Split(user.Scopes, ",")
|
userScopes := strings.Split(user.Scopes, ",")
|
||||||
|
sessionToken, err := uuid.NewV7()
|
||||||
|
if err != nil {
|
||||||
|
return h.InternalServerErrorResponse(c, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
jwt, err := h.generateJwtWithExp(username, h.config.ServerAddress, userScopes, user.ID, expiresAt)
|
jwt, err := h.generateJwtWithExp(username, h.config.ServerAddress, sessionToken.String(), userScopes, user.ID, expiresAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return h.InternalServerErrorResponse(c, err.Error())
|
return h.InternalServerErrorResponse(c, err.Error())
|
||||||
}
|
}
|
||||||
@ -109,6 +114,7 @@ func (h *Handler) AuthLogin(c echo.Context) error {
|
|||||||
Token: jwt,
|
Token: jwt,
|
||||||
Type: "Bearer",
|
Type: "Bearer",
|
||||||
RefreshToken: refresh,
|
RefreshToken: refresh,
|
||||||
|
SessionToken: sessionToken.String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,8 +130,12 @@ func (h *Handler) createAdminToken(c echo.Context, password string) error {
|
|||||||
}
|
}
|
||||||
var userScopes []string
|
var userScopes []string
|
||||||
userScopes = append(userScopes, domain.ScopeAll)
|
userScopes = append(userScopes, domain.ScopeAll)
|
||||||
|
sessionToken, err := uuid.NewV7()
|
||||||
|
if err != nil {
|
||||||
|
return h.InternalServerErrorResponse(c, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
token, err := h.generateJwt("admin", h.config.ServerAddress, userScopes, -1)
|
token, err := h.generateJwt("admin", h.config.ServerAddress, sessionToken.String(), userScopes, -1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return h.InternalServerErrorResponse(c, err.Error())
|
return h.InternalServerErrorResponse(c, err.Error())
|
||||||
}
|
}
|
||||||
@ -173,7 +183,7 @@ func (h *Handler) RefreshJwtToken(c echo.Context) error {
|
|||||||
}
|
}
|
||||||
userScopes := strings.Split(user.Scopes, ",")
|
userScopes := strings.Split(user.Scopes, ",")
|
||||||
|
|
||||||
jwt, err := h.generateJwtWithExp(request.Username, h.config.ServerAddress, userScopes, user.ID, time.Now().Add(time.Hour*48))
|
jwt, err := h.generateJwtWithExp(request.Username, h.config.ServerAddress, "", userScopes, user.ID, time.Now().Add(time.Hour*48))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return h.InternalServerErrorResponse(c, err.Error())
|
return h.InternalServerErrorResponse(c, err.Error())
|
||||||
}
|
}
|
||||||
@ -250,7 +260,6 @@ func (h *Handler) RemoveScopes(c echo.Context) error {
|
|||||||
err = (&echo.DefaultBinder{}).BindBody(c, &request)
|
err = (&echo.DefaultBinder{}).BindBody(c, &request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.WriteError(c, err, http.StatusBadRequest)
|
h.WriteError(c, err, http.StatusBadRequest)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.repo.Users.RemoveScopes(c.Request().Context(), request.Username, request.Scopes)
|
err = h.repo.Users.RemoveScopes(c.Request().Context(), request.Username, request.Scopes)
|
||||||
@ -262,3 +271,26 @@ func (h *Handler) RemoveScopes(c echo.Context) error {
|
|||||||
Message: "OK",
|
Message: "OK",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Revokes the current session token and replaces it with a new one.
|
||||||
|
// @Router /v1/users/refresh/sessionToken [post]
|
||||||
|
// @Tags Users
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} domain.BaseResponse
|
||||||
|
// @Failure 400 {object} domain.BaseResponse
|
||||||
|
// @Failure 500 {object} domain.BaseResponse
|
||||||
|
// @Security Bearer
|
||||||
|
func (h *Handler) LogoutEverywhere(c echo.Context) error {
|
||||||
|
token, err := h.getJwtTokenFromContext(c)
|
||||||
|
if err != nil {
|
||||||
|
return h.WriteError(c, err, http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = token.IsValid(domain.ScopeAll)
|
||||||
|
if err != nil {
|
||||||
|
return h.WriteError(c, err, http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.String(http.StatusInternalServerError, "Not Implemented")
|
||||||
|
}
|
@ -14,17 +14,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TableName string = "users"
|
usersTableName string = "users"
|
||||||
ErrUserNotFound string = "requested user was not found"
|
ErrUserNotFound string = "requested user was not found"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Users interface {
|
type Users interface {
|
||||||
GetByName(ctx context.Context, name string) (entity.UserEntity, error)
|
GetByName(ctx context.Context, name string) (entity.UserEntity, error)
|
||||||
Create(ctx context.Context, name, password, scope string) (int64, error)
|
Create(ctx context.Context, name, password, sessionTOken, scope string) (int64, error)
|
||||||
Update(ctx context.Context, id int, entity entity.UserEntity) error
|
Update(ctx context.Context, id int, entity entity.UserEntity) error
|
||||||
UpdatePassword(ctx context.Context, name, password string) error
|
UpdatePassword(ctx context.Context, name, password string) error
|
||||||
CheckUserHash(ctx context.Context, name, password string) error
|
CheckUserHash(ctx context.Context, name, password string) error
|
||||||
UpdateScopes(ctx context.Context, name, scope string) error
|
UpdateScopes(ctx context.Context, name, scope string) error
|
||||||
|
UpdateSessionToken(ctx context.Context, name, sessionToken string) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new instance of UserRepository with the bound sql
|
// Creates a new instance of UserRepository with the bound sql
|
||||||
@ -58,7 +59,7 @@ func (ur userRepository) GetByName(ctx context.Context, name string) (entity.Use
|
|||||||
return data[0], nil
|
return data[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ur userRepository) Create(ctx context.Context, name, password, scope string) (int64, error) {
|
func (ur userRepository) Create(ctx context.Context, name, password, sessionToken, scope string) (int64, error) {
|
||||||
passwordBytes := []byte(password)
|
passwordBytes := []byte(password)
|
||||||
hash, err := bcrypt.GenerateFromPassword(passwordBytes, bcrypt.DefaultCost)
|
hash, err := bcrypt.GenerateFromPassword(passwordBytes, bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -68,8 +69,8 @@ func (ur userRepository) Create(ctx context.Context, name, password, scope strin
|
|||||||
dt := time.Now()
|
dt := time.Now()
|
||||||
queryBuilder := sqlbuilder.NewInsertBuilder()
|
queryBuilder := sqlbuilder.NewInsertBuilder()
|
||||||
queryBuilder.InsertInto("users")
|
queryBuilder.InsertInto("users")
|
||||||
queryBuilder.Cols("Name", "Hash", "UpdatedAt", "CreatedAt", "DeletedAt", "Scopes")
|
queryBuilder.Cols("Name", "Hash", "UpdatedAt", "CreatedAt", "DeletedAt", "Scopes", "SessionToken")
|
||||||
queryBuilder.Values(name, string(hash), dt, dt, time.Time{}, scope)
|
queryBuilder.Values(name, string(hash), dt, dt, time.Time{}, scope, sessionToken)
|
||||||
query, args := queryBuilder.Build()
|
query, args := queryBuilder.Build()
|
||||||
|
|
||||||
_, err = ur.connection.ExecContext(ctx, query, args...)
|
_, err = ur.connection.ExecContext(ctx, query, args...)
|
||||||
@ -91,11 +92,35 @@ func (ur userRepository) UpdatePassword(ctx context.Context, name, password stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
queryBuilder := sqlbuilder.NewUpdateBuilder()
|
queryBuilder := sqlbuilder.NewUpdateBuilder()
|
||||||
queryBuilder.Update(TableName)
|
queryBuilder.Update(usersTableName)
|
||||||
//queryBuilder.Set
|
//queryBuilder.Set
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ur userRepository) UpdateSessionToken(ctx context.Context, name, sessionToken string) (int64, error) {
|
||||||
|
_, err := ur.GetByName(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
q := sqlbuilder.NewUpdateBuilder()
|
||||||
|
q.Update(usersTableName)
|
||||||
|
q.Set(
|
||||||
|
q.Equal("SessionToken", sessionToken),
|
||||||
|
)
|
||||||
|
q.Where(
|
||||||
|
q.Equal("Name", name),
|
||||||
|
)
|
||||||
|
|
||||||
|
query, args := q.Build()
|
||||||
|
rowsUpdates, err := ur.connection.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rowsUpdates.RowsAffected()
|
||||||
|
}
|
||||||
|
|
||||||
// If the hash matches what we have in the database, an error will not be returned.
|
// If the hash matches what we have in the database, an error will not be returned.
|
||||||
// If the user does not exist or the hash does not match, an error will be returned
|
// If the user does not exist or the hash does not match, an error will be returned
|
||||||
func (ur userRepository) CheckUserHash(ctx context.Context, name, password string) error {
|
func (ur userRepository) CheckUserHash(ctx context.Context, name, password string) error {
|
||||||
@ -141,7 +166,8 @@ func (ur userRepository) processRows(rows *sql.Rows) []entity.UserEntity {
|
|||||||
var updatedAt time.Time
|
var updatedAt time.Time
|
||||||
var deletedAt sql.NullTime
|
var deletedAt sql.NullTime
|
||||||
var scopes string
|
var scopes string
|
||||||
err := rows.Scan(&id, &createdAt, &updatedAt, &deletedAt, &username, &hash, &scopes)
|
var sessionToken string
|
||||||
|
err := rows.Scan(&id, &createdAt, &updatedAt, &deletedAt, &username, &hash, &scopes, &sessionToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
@ -153,6 +179,7 @@ func (ur userRepository) processRows(rows *sql.Rows) []entity.UserEntity {
|
|||||||
Hash: hash,
|
Hash: hash,
|
||||||
Scopes: scopes,
|
Scopes: scopes,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
|
SessionToken: sessionToken,
|
||||||
}
|
}
|
||||||
if deletedAt.Valid {
|
if deletedAt.Valid {
|
||||||
item.DeletedAt = deletedAt.Time
|
item.DeletedAt = deletedAt.Time
|
||||||
|
@ -21,7 +21,7 @@ func TestCanCreateNewUser(t *testing.T) {
|
|||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
repo := repository.NewUserRepository(db)
|
repo := repository.NewUserRepository(db)
|
||||||
updated, err := repo.Create(context.Background(), "testing", "NotSecure", "placeholder")
|
updated, err := repo.Create(context.Background(), "testing", "NotSecure", "sessionToken", "placeholder")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
@ -38,7 +38,7 @@ func TestCanFindUserInTable(t *testing.T) {
|
|||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
repo := repository.NewUserRepository(db)
|
repo := repository.NewUserRepository(db)
|
||||||
updated, err := repo.Create(context.Background(), "testing", "NotSecure", "placeholder")
|
updated, err := repo.Create(context.Background(), "testing", "NotSecure", "sessionToken", "placeholder")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
@ -4,11 +4,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.jamestombleson.com/jtom38/newsbot-api/domain"
|
"git.jamestombleson.com/jtom38/newsbot-api/domain"
|
||||||
"git.jamestombleson.com/jtom38/newsbot-api/internal/entity"
|
"git.jamestombleson.com/jtom38/newsbot-api/internal/entity"
|
||||||
"git.jamestombleson.com/jtom38/newsbot-api/internal/repository"
|
"git.jamestombleson.com/jtom38/newsbot-api/internal/repository"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
@ -25,7 +27,8 @@ type UserServices interface {
|
|||||||
GetUser(ctx context.Context, username string) (entity.UserEntity, error)
|
GetUser(ctx context.Context, username string) (entity.UserEntity, error)
|
||||||
AddScopes(ctx context.Context, username string, scopes []string) error
|
AddScopes(ctx context.Context, username string, scopes []string) error
|
||||||
RemoveScopes(ctx context.Context, username string, scopes []string) error
|
RemoveScopes(ctx context.Context, username string, scopes []string) error
|
||||||
Create(ctx context.Context, name, password, scope string) (entity.UserEntity, error)
|
Create(ctx context.Context, name, password, sessionToken, scope string) (entity.UserEntity, error)
|
||||||
|
NewSessionToken(ctx context.Context, name string) error
|
||||||
CheckPasswordForRequirements(password string) error
|
CheckPasswordForRequirements(password string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,16 +128,34 @@ func (us UserService) doesScopeExist(scopes []string, target string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us UserService) Create(ctx context.Context, name, password, scope string) (entity.UserEntity, error) {
|
func (us UserService) Create(ctx context.Context, name, password, sessionToken, scope string) (entity.UserEntity, error) {
|
||||||
err := us.CheckPasswordForRequirements(password)
|
err := us.CheckPasswordForRequirements(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return entity.UserEntity{}, err
|
return entity.UserEntity{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
us.repo.Create(ctx, name, password, domain.ScopeArticleRead)
|
us.repo.Create(ctx, name, password, sessionToken, domain.ScopeArticleRead)
|
||||||
return entity.UserEntity{}, nil
|
return entity.UserEntity{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (us UserService) NewSessionToken(ctx context.Context, name string) error {
|
||||||
|
token, err := uuid.NewV7()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := us.repo.UpdateSessionToken(ctx, name, token.String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if rows != 1 {
|
||||||
|
return fmt.Errorf("UserService.NewSessionToken %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (us UserService) CheckPasswordForRequirements(password string) error {
|
func (us UserService) CheckPasswordForRequirements(password string) error {
|
||||||
err := us.checkPasswordLength(password)
|
err := us.checkPasswordLength(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7,12 +7,12 @@ import (
|
|||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
|
|
||||||
"git.jamestombleson.com/jtom38/newsbot-api/internal/database"
|
//"git.jamestombleson.com/jtom38/newsbot-api/internal/database"
|
||||||
"git.jamestombleson.com/jtom38/newsbot-api/internal/services"
|
"git.jamestombleson.com/jtom38/newsbot-api/internal/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Cron struct {
|
type Cron struct {
|
||||||
Db *database.Queries
|
//Db *database.Queries
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
timer *cron.Cron
|
timer *cron.Cron
|
||||||
repo services.RepositoryService
|
repo services.RepositoryService
|
||||||
|
@ -8,7 +8,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.jamestombleson.com/jtom38/newsbot-api/internal/database"
|
"git.jamestombleson.com/jtom38/newsbot-api/internal/entity"
|
||||||
|
//"git.jamestombleson.com/jtom38/newsbot-api/internal/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
type discordField struct {
|
type discordField struct {
|
||||||
@ -63,11 +64,11 @@ const (
|
|||||||
|
|
||||||
type Discord struct {
|
type Discord struct {
|
||||||
Subscriptions []string
|
Subscriptions []string
|
||||||
article database.Article
|
article entity.ArticleEntity
|
||||||
Message *DiscordMessage
|
Message *DiscordMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDiscordWebHookMessage(Article database.Article) Discord {
|
func NewDiscordWebHookMessage(Article entity.ArticleEntity) Discord {
|
||||||
return Discord{
|
return Discord{
|
||||||
article: Article,
|
article: Article,
|
||||||
}
|
}
|
||||||
|
@ -5,22 +5,19 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.jamestombleson.com/jtom38/newsbot-api/internal/database"
|
//"git.jamestombleson.com/jtom38/newsbot-api/internal/database"
|
||||||
|
"git.jamestombleson.com/jtom38/newsbot-api/internal/entity"
|
||||||
"git.jamestombleson.com/jtom38/newsbot-api/internal/services/output"
|
"git.jamestombleson.com/jtom38/newsbot-api/internal/services/output"
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
article database.Article = database.Article{
|
article entity.ArticleEntity = entity.ArticleEntity{
|
||||||
ID: uuid.New(),
|
ID: 999,
|
||||||
Sourceid: uuid.New(),
|
SourceID: 1,
|
||||||
Tags: "unit, testing",
|
Tags: "unit, testing",
|
||||||
Title: "Demo",
|
Title: "Demo",
|
||||||
Url: "https://github.com/jtom38/newsbot.collector.api",
|
Url: "https://github.com/jtom38/newsbot.collector.api",
|
||||||
//Pubdate: time.Now(),
|
|
||||||
Videoheight: 0,
|
|
||||||
Videowidth: 0,
|
|
||||||
Description: "Hello World",
|
Description: "Hello World",
|
||||||
}
|
}
|
||||||
blank string = ""
|
blank string = ""
|
||||||
|
Loading…
Reference in New Issue
Block a user