Adds current plan implementation
This commit is contained in:
parent
d37c53c60b
commit
8c17aa9d6d
@ -17,6 +17,9 @@ type Store interface {
|
|||||||
SelectActionsByPlanID(plan *Plan, userID int) ([]*Action, error)
|
SelectActionsByPlanID(plan *Plan, userID int) ([]*Action, error)
|
||||||
SelectUserByUsername(username string) (*User, error)
|
SelectUserByUsername(username string) (*User, error)
|
||||||
InsertUser(user *User) (int, error)
|
InsertUser(user *User) (int, error)
|
||||||
|
SelectPrimaryPlan(userID int) (*PrimaryPlan, error)
|
||||||
|
InsertPrimaryPlan(primaryPlan *PrimaryPlan, userID int) error
|
||||||
|
UpdatePrimaryPlan(primaryPlan *PrimaryPlan, userID int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Model represents a current model item.
|
// Model represents a current model item.
|
||||||
|
23
models/primary_plan.go
Normal file
23
models/primary_plan.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// PrimaryPlan represents the primary plan ID for a particular user ID.
|
||||||
|
type PrimaryPlan struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
PlanID int64 `json:"plan_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrimaryPlan returns the primary plan for a provided user ID in the given model.
|
||||||
|
func (m *Model) PrimaryPlan(userID int) (*PrimaryPlan, error) {
|
||||||
|
pp, err := m.SelectPrimaryPlan(userID)
|
||||||
|
return pp, wrapNotFound(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddPrimaryPlan inserts a given primary plan into the store, returning nothing.
|
||||||
|
func (m *Model) AddPrimaryPlan(pp *PrimaryPlan, userID int) error {
|
||||||
|
return m.InsertPrimaryPlan(pp, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SavePrimaryPlan saves and updates a primary plan.
|
||||||
|
func (m *Model) SavePrimaryPlan(pp *PrimaryPlan, userID int) error {
|
||||||
|
return m.UpdatePrimaryPlan(pp, userID)
|
||||||
|
}
|
160
routes/primary_plans.go
Normal file
160
routes/primary_plans.go
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"gitea.deepak.science/deepak/gogmagog/models"
|
||||||
|
"gitea.deepak.science/deepak/gogmagog/tokens"
|
||||||
|
"github.com/go-chi/chi"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewPrimaryPlanRouter returns a new primary plan router
|
||||||
|
func NewPrimaryPlanRouter(m *models.Model) http.Handler {
|
||||||
|
router := chi.NewRouter()
|
||||||
|
router.Get("/", getPrimaryPlanFunc(m))
|
||||||
|
router.Post("/", postPrimaryPlanFunc(m))
|
||||||
|
router.Put("/", putPrimaryPlanFunc(m))
|
||||||
|
return router
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPrimaryPlanFunc(m *models.Model) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID, userErr := tokens.GetUserID(r.Context())
|
||||||
|
if userErr != nil {
|
||||||
|
unauthorizedHandler(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pp, err := m.PrimaryPlan(userID)
|
||||||
|
if err != nil {
|
||||||
|
if models.IsNotFoundError(err) {
|
||||||
|
notFoundHandler(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
serverError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
if err := json.NewEncoder(w).Encode(pp); err != nil {
|
||||||
|
serverError(w, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type createPrimaryPlanResponse struct {
|
||||||
|
CreatedPrimaryPlan *models.PrimaryPlan `json:"created_current_plan"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func postPrimaryPlanFunc(m *models.Model) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
userID, err := tokens.GetUserID(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
unauthorizedHandler(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Body = http.MaxBytesReader(w, r.Body, 1024)
|
||||||
|
dec := json.NewDecoder(r.Body)
|
||||||
|
dec.DisallowUnknownFields()
|
||||||
|
var pp models.PrimaryPlan
|
||||||
|
err = dec.Decode(&pp)
|
||||||
|
if err != nil {
|
||||||
|
badRequestError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = dec.Decode(&struct{}{})
|
||||||
|
if err != io.EOF {
|
||||||
|
badRequestError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newPP := &models.PrimaryPlan{
|
||||||
|
PlanID: pp.PlanID,
|
||||||
|
UserID: int64(userID),
|
||||||
|
}
|
||||||
|
err = m.AddPrimaryPlan(newPP, userID)
|
||||||
|
if err != nil {
|
||||||
|
serverError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
finishedPP, err := m.PrimaryPlan(userID)
|
||||||
|
if err != nil {
|
||||||
|
serverError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &createPrimaryPlanResponse{
|
||||||
|
CreatedPrimaryPlan: finishedPP,
|
||||||
|
}
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||||
|
serverError(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type updatePrimaryPlanResponse struct {
|
||||||
|
UpdatedPrimaryPlan *models.PrimaryPlan `json:"updated_current_plan"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func putPrimaryPlanFunc(m *models.Model) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
userID, err := tokens.GetUserID(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
unauthorizedHandler(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = m.PrimaryPlan(userID)
|
||||||
|
if models.IsNotFoundError(err) {
|
||||||
|
notFoundHandler(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Body = http.MaxBytesReader(w, r.Body, 1024)
|
||||||
|
dec := json.NewDecoder(r.Body)
|
||||||
|
dec.DisallowUnknownFields()
|
||||||
|
var pp models.PrimaryPlan
|
||||||
|
err = dec.Decode(&pp)
|
||||||
|
if err != nil {
|
||||||
|
badRequestError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = dec.Decode(&struct{}{})
|
||||||
|
if err != io.EOF {
|
||||||
|
badRequestError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newPP := &models.PrimaryPlan{
|
||||||
|
PlanID: pp.PlanID,
|
||||||
|
UserID: int64(userID),
|
||||||
|
}
|
||||||
|
err = m.SavePrimaryPlan(newPP, userID)
|
||||||
|
if err != nil {
|
||||||
|
serverError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
newPP, err = m.PrimaryPlan(userID)
|
||||||
|
if err != nil {
|
||||||
|
serverError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &updatePrimaryPlanResponse{
|
||||||
|
UpdatedPrimaryPlan: newPP,
|
||||||
|
}
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||||
|
serverError(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ func NewRouter(m *models.Model, tok tokens.Toker) http.Handler {
|
|||||||
r.Mount("/actions", NewActionRouter(m))
|
r.Mount("/actions", NewActionRouter(m))
|
||||||
r.Mount("/plans", NewPlanRouter(m))
|
r.Mount("/plans", NewPlanRouter(m))
|
||||||
r.Mount("/me", NewCurrentUserRouter(m))
|
r.Mount("/me", NewCurrentUserRouter(m))
|
||||||
|
r.Mount("/currentPlan", NewPrimaryPlanRouter(m))
|
||||||
})
|
})
|
||||||
router.Mount("/auth", NewAuthRouter(m, tok))
|
router.Mount("/auth", NewAuthRouter(m, tok))
|
||||||
router.Mount("/health", newHealthRouter(m))
|
router.Mount("/health", newHealthRouter(m))
|
||||||
|
@ -57,6 +57,24 @@ func (e *errorStore) InsertUser(user *models.User) (int, error) {
|
|||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *errorStore) SelectPrimaryPlan(userID int) (*models.PrimaryPlan, error) {
|
||||||
|
return nil, e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *errorStore) InsertPrimaryPlan(primaryPlan *models.PrimaryPlan, userID int) error {
|
||||||
|
if e.errorOnInsert {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *errorStore) UpdatePrimaryPlan(primaryPlan *models.PrimaryPlan, userID int) error {
|
||||||
|
if e.errorOnInsert {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *errorStore) ConnectionLive() error {
|
func (e *errorStore) ConnectionLive() error {
|
||||||
return e.error
|
return e.error
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package store
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"gitea.deepak.science/deepak/gogmagog/models"
|
"gitea.deepak.science/deepak/gogmagog/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ type inMemoryStore struct {
|
|||||||
actions []*models.Action
|
actions []*models.Action
|
||||||
plans []*models.Plan
|
plans []*models.Plan
|
||||||
users []*models.User
|
users []*models.User
|
||||||
|
primaryPlans []*models.PrimaryPlan
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInMemoryStore provides a purely in memory store, for testing purposes only, with no persistence.
|
// GetInMemoryStore provides a purely in memory store, for testing purposes only, with no persistence.
|
||||||
@ -98,6 +100,37 @@ func (store *inMemoryStore) InsertPlan(plan *models.Plan, userID int) (int, erro
|
|||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (store *inMemoryStore) SelectPrimaryPlan(userID int) (*models.PrimaryPlan, error) {
|
||||||
|
for _, primaryPlan := range store.primaryPlans {
|
||||||
|
if userID == int(primaryPlan.UserID) {
|
||||||
|
return primaryPlan, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, sql.ErrNoRows
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store *inMemoryStore) InsertPrimaryPlan(primaryPlan *models.PrimaryPlan, userID int) error {
|
||||||
|
_, err := store.SelectPrimaryPlan(userID)
|
||||||
|
if err != sql.ErrNoRows {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("Can't insert primary plan")
|
||||||
|
}
|
||||||
|
|
||||||
|
store.primaryPlans = append(store.primaryPlans, &models.PrimaryPlan{PlanID: int64(primaryPlan.PlanID), UserID: int64(userID)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store *inMemoryStore) UpdatePrimaryPlan(primaryPlan *models.PrimaryPlan, userID int) error {
|
||||||
|
current, err := store.SelectPrimaryPlan(userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
current.PlanID = primaryPlan.PlanID
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (store *inMemoryStore) ConnectionLive() error {
|
func (store *inMemoryStore) ConnectionLive() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
DROP TABLE IF EXISTS actions;
|
DROP TABLE IF EXISTS actions;
|
||||||
|
DROP TABLE IF EXISTS user_primary_plan;
|
||||||
DROP TABLE IF EXISTS plans;
|
DROP TABLE IF EXISTS plans;
|
||||||
DROP TABLE IF EXISTS users;
|
DROP TABLE IF EXISTS users;
|
||||||
|
|
||||||
|
@ -12,7 +12,14 @@ CREATE TABLE IF NOT EXISTS plans(
|
|||||||
plan_date DATE NOT NULL,
|
plan_date DATE NOT NULL,
|
||||||
user_id int REFERENCES users(user_id),
|
user_id int REFERENCES users(user_id),
|
||||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
|
UNIQUE (user_id, plan_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS user_primary_plan(
|
||||||
|
user_id int PRIMARY KEY,
|
||||||
|
plan_id int,
|
||||||
|
FOREIGN KEY (user_id, plan_id) REFERENCES plans(user_id, plan_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS actions(
|
CREATE TABLE IF NOT EXISTS actions(
|
||||||
|
@ -174,3 +174,51 @@ func (store *postgresStore) InsertUser(user *models.User) (int, error) {
|
|||||||
}
|
}
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (store *postgresStore) SelectPrimaryPlan(userID int) (*models.PrimaryPlan, error) {
|
||||||
|
pp := models.PrimaryPlan{}
|
||||||
|
queryString := store.db.Rebind(`SELECT user_id, plan_id FROM user_primary_plan WHERE user_id = ?`)
|
||||||
|
err := store.db.Get(&pp, queryString, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &pp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store *postgresStore) InsertPrimaryPlan(primaryPlan *models.PrimaryPlan, userID int) error {
|
||||||
|
queryString := store.db.Rebind("INSERT INTO user_primary_plan (user_id, plan_id) VALUES (?, ?) RETURNING user_id")
|
||||||
|
tx := store.db.MustBegin()
|
||||||
|
var id int
|
||||||
|
err := tx.Get(&id, queryString, primaryPlan.PlanID, userID)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store *postgresStore) UpdatePrimaryPlan(primaryPlan *models.PrimaryPlan, userID int) error {
|
||||||
|
query := `UPDATE user_primary_plan SET
|
||||||
|
plan_id = :plan_id
|
||||||
|
WHERE user_id = :user_id`
|
||||||
|
tx := store.db.MustBegin()
|
||||||
|
ppToUse := &models.PrimaryPlan{
|
||||||
|
PlanID: primaryPlan.PlanID,
|
||||||
|
UserID: int64(userID),
|
||||||
|
}
|
||||||
|
_, err := store.db.NamedExec(query, ppToUse)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user