Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authentication middleware added. Added feed entity's schema, and handler. #6

Merged
merged 1 commit into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions auth_middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import (
"fmt"
"net/http"

"github.com/itishrishikesh/gofeed/auth"
"github.com/itishrishikesh/gofeed/constants"
"github.com/itishrishikesh/gofeed/internal/database"
)

type authHeader func(http.ResponseWriter, *http.Request, database.User)

func (config *apiConfig) authMiddleware(handler authHeader) http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
apiKey, err := auth.GetAPIKey(request.Header)
if err != nil {
respondWithError(writer, constants.HTTP_FORBIDDEN, fmt.Sprintf("E#1OV41H - Authentication Error: %v", err))
return
}
user, err := config.DB.GetUserByAPIKey(request.Context(), apiKey)
if err != nil {
respondWithError(writer, constants.HTTP_BAD_REQUEST, fmt.Sprintf("E#1OV44M - Couldn't get user: %v", err))
return
}
handler(writer, request, user)
}
}
2 changes: 2 additions & 0 deletions constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ package constants
const CONTENT_TYPE string = "Content-Type"
const APPLICATION_JSON string = "application/json"
const HTTP_SUCCESS int = 200
const HTTP_CREATED int = 200
const HTTP_ERROR int = 500
const HTTP_BAD_REQUEST int = 400
const HTTP_FORBIDDEN int = 400
77 changes: 77 additions & 0 deletions feed_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package main

import (
"encoding/json"
"fmt"
"log"
"net/http"
"time"

"github.com/google/uuid"
"github.com/itishrishikesh/gofeed/constants"
"github.com/itishrishikesh/gofeed/internal/database"
)

func (apiCfg *apiConfig) createFeedHandler(writer http.ResponseWriter, request *http.Request, user database.User) {
type parameters struct {
Name string `json:"name"`
URL string `json:"url"`
}
params := parameters{}
decoder := json.NewDecoder(request.Body)
err := decoder.Decode(&params)
if err != nil {
respondWithError(writer, constants.HTTP_BAD_REQUEST, "Error parsing JSON")
log.Println("D#1OV4W5 - User passed incorrect JSON")
return
}
feed, err := apiCfg.DB.CreateFeed(request.Context(), database.CreateFeedParams{
ID: uuid.New(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Name: params.Name,
Url: params.URL,
UserID: user.ID,
})
if err != nil {
respondWithError(writer, constants.HTTP_BAD_REQUEST, fmt.Sprintf("E#1OV5DR - Couldn't create feed %v", err))
return
}

respondWithJSON(writer, constants.HTTP_CREATED, databaseFeedToFeed(feed))
}

func (config *apiConfig) getFeedsHandler(writer http.ResponseWriter, request *http.Request) {
feeds, err := config.DB.GetFeed(request.Context())
if err != nil {
respondWithError(writer, constants.HTTP_BAD_REQUEST, fmt.Sprintf("E#1OV63D - Couldn't get feed %v", err))
return
}
respondWithJSON(writer, constants.HTTP_CREATED, databaseFeedToFeeds(feeds))
}

func (config *apiConfig) createFeedFollowHandler(writer http.ResponseWriter, request *http.Request, user database.User) {
type parameters struct {
FeedID uuid.UUID `json:"feed_id"`
}
params := parameters{}
decoder := json.NewDecoder(request.Body)
err := decoder.Decode(&params)
if err != nil {
respondWithError(writer, constants.HTTP_BAD_REQUEST, "Error parsing JSON")
log.Println("D#1OV7DL - User passed incorrect JSON")
return
}
feedFollow, err := config.DB.CreateFeedFollow(request.Context(), database.CreateFeedFollowParams{
ID: uuid.New(),
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
UserID: user.ID,
FeedID: params.FeedID,
})
if err != nil {
respondWithError(writer, constants.HTTP_BAD_REQUEST, fmt.Sprintf("E#1OV7DV - Couldn't create feed follow %v", err))
return
}
respondWithJSON(writer, constants.HTTP_CREATED, databaseFeedFollowToFeedFollow(feedFollow))
}
83 changes: 83 additions & 0 deletions internal/database/feeds.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions internal/database/feeds_follow.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions internal/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ func main() {
v1Router.Get("/healthz", healthCheckHandler)
v1Router.Get("/err", errorHandler)
v1Router.Post("/users", apiCfg.createUserHandler)
v1Router.Get("/users", apiCfg.getUserHandler)
v1Router.Get("/users", apiCfg.authMiddleware(apiCfg.getUserHandler))
v1Router.Post("/feeds", apiCfg.authMiddleware(apiCfg.createFeedHandler))
v1Router.Get("/feeds", apiCfg.getFeedsHandler)
v1Router.Post("/feedfollow", apiCfg.authMiddleware(apiCfg.createFeedFollowHandler))
router.Mount("/v1", v1Router)

server := &http.Server{
Expand Down
46 changes: 46 additions & 0 deletions models.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,49 @@ func databaseUserToUser(dbUser database.User) User {
ApiKey: dbUser.ApiKey,
}
}

type Feed struct {
ID uuid.UUID `json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Name string `json:"name"`
Url string `json:"url"`
UserID uuid.UUID `json:"user_id"`
}

func databaseFeedToFeed(dbFeed database.Feed) Feed {
return Feed{
ID: dbFeed.ID,
CreatedAt: dbFeed.CreatedAt,
UpdatedAt: dbFeed.UpdatedAt,
Name: dbFeed.Name,
Url: dbFeed.Url,
UserID: dbFeed.UserID,
}
}

func databaseFeedToFeeds(dbFeeds []database.Feed) []Feed {
feeds := []Feed{}
for _, dbFeed := range dbFeeds {
feeds = append(feeds, databaseFeedToFeed(dbFeed))
}
return feeds
}

type FeedFollow struct {
ID uuid.UUID `json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
UserID uuid.UUID `json:"user_id"`
FeedID uuid.UUID `json:"feed_id"`
}

func databaseFeedFollowToFeedFollow(dbFeedFollow database.FeedFollow) FeedFollow {
return FeedFollow{
ID: dbFeedFollow.ID,
CreatedAt: dbFeedFollow.CreatedAt,
UpdatedAt: dbFeedFollow.UpdatedAt,
UserID: dbFeedFollow.UserID,
FeedID: dbFeedFollow.FeedID,
}
}
7 changes: 7 additions & 0 deletions sql/queries/feeds.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- name: CreateFeed :one
INSERT INTO feeds (id, created_at, updated_at, name, url, user_id)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING *;

-- name: GetFeed :many
SELECT * from feeds;
4 changes: 4 additions & 0 deletions sql/queries/feeds_follow.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- name: CreateFeedFollow :one
INSERT INTO feed_follows (id, created_at, updated_at, user_id, feed_id)
VALUES ($1, $2, $3, $4, $5)
RETURNING *;
12 changes: 12 additions & 0 deletions sql/schema/003_feeds.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- +goose Up
CREATE TABLE feeds (
id UUID PRIMARY KEY,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
name TEXT NOT NULL,
url TEXT UNIQUE NOT NULL,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE
);

-- +goose Down
DROP TABLE feeds;
12 changes: 12 additions & 0 deletions sql/schema/004_feed_follows.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- +goose Up
CREATE TABLE feed_follows (
id UUID PRIMARY KEY,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
feed_id UUID NOT NULL REFERENCES feeds(id) ON DELETE CASCADE,
UNIQUE(user_id, feed_id)
);

-- +goose Down
DROP TABLE feed_follows;
Loading