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

feat: adding new tables and resolvers #92

Closed
wants to merge 1 commit into from
Closed
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
*.env*
!*.env-example
**/.DS_Store
.vscode/launch.json
.vscode/settings.json
87 changes: 48 additions & 39 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

The backend is comprised of a GraphQL API and an ETL process both written in Go.

## Business Logic

```mermaid
erDiagram
Question }|--|| Function : has

```

## Developer Requirement and Config

- Go ~>1.22.0
Expand Down Expand Up @@ -40,47 +48,48 @@ The API is designed to serve with TLS when a certificate and key are provided, o
```mermaid
sequenceDiagram

box Transparent
participant Client
end
box Gray HTTP
participant Handler
participant Auth Middleware
end
box Gray GraphQL
participant Relay
participant Resolver
end
box Gray Business Logic
participant Controller
end
box Gray Data
participant Model
participant PGX
end
Client->>Handler: Request
Handler->>Auth Middleware: Request
Note over Auth Middleware: Validates JWT
break Invalid JWT
Auth Middleware ->> Client: Response 401
end
destroy Auth Middleware
Auth Middleware ->> Relay: Request
Relay ->> Resolver: r w/ context
Resolver ->> Controller: r w/ context
Controller ->> Model: FindXyz()
note over PGX: Postgre driver
Model ->> PGX: prepared statement
PGX ->> Postgre: query
Postgre ->> PGX: data
PGX ->> Model: data
Model ->> Controller: data structs
Controller ->> Resolver: data structs
Resolver ->> Relay: data structs
Relay ->> Handler: response
Handler ->> Client: json
box Transparent
participant Client
end
box Gray HTTP
participant Handler
participant Auth Middleware
end
box Gray GraphQL
participant Relay
participant Resolver
end
box Gray Business Logic
participant Controller
end
box Gray Data
participant Model
participant PGX
end
Client->>Handler: Request
Handler->>Auth Middleware: Request
Note over Auth Middleware: Validates JWT
break Invalid JWT
Auth Middleware ->> Client: Response 401
end
destroy Auth Middleware
Auth Middleware ->> Relay: Request
Relay ->> Resolver: r w/ context
Resolver ->> Controller: r w/ context
Controller ->> Model: FindXyz()
note over PGX: Postgre driver
Model ->> PGX: prepared statement
PGX ->> Postgre: query
Postgre ->> PGX: data
PGX ->> Model: data
Model ->> Controller: data structs
Controller ->> Resolver: data structs
Resolver ->> Relay: data structs
Relay ->> Handler: response
Handler ->> Client: json
```

<!-- TODO: explain the above diagram -->

### Docker

Expand Down
38 changes: 28 additions & 10 deletions backend/cmd/api/internal/graph/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ type Query {
user(userid: ID!): User!
}

type Mutation {
saveUser(userid: ID, email: String!, fullname: String!, role: String!): UserMutationResponse!
saveFunctionScore(scoreid: ID, fismasystemid: Int!, functionid: Int!, score: Float!, notes: String): FunctionScoreMutationReponse!
assignFismaSystems(userid: String!, fismasystemids: [Int!]!): UserMutationResponse!
unassignFismaSystems(userid: String!, fismasystemids: [Int!]!): UserMutationResponse!
}

type FismaSystem {
fismasystemid: ID!
fismauid: String!
Expand All @@ -35,14 +42,20 @@ type FismaSystem {

type Function {
functionid: ID!
pillar: String
name: String
description: String
traditional: String
initial: String
advanced: String
optimal: String
datacenterenvironment: String
options: [FunctionOption!]!
question: Question
pillar: Pillar
}

type FunctionOption {
functionoptionid: ID!
functionid: Int!
score: Int!
optionname: String!
description: String!
}

type FunctionScore {
Expand All @@ -63,11 +76,16 @@ type User {
fismasystemids: [Int]!
}

type Mutation {
saveUser(userid: ID, email: String!, fullname: String!, role: String!): UserMutationResponse!
saveFunctionScore(scoreid: ID, fismasystemid: Int!, functionid: Int!, score: Float!, notes: String): FunctionScoreMutationReponse!
assignFismaSystems(userid: String!, fismasystemids: [Int!]!): UserMutationResponse!
unassignFismaSystems(userid: String!, fismasystemids: [Int!]!): UserMutationResponse!
type Question {
questionid: ID!
question: String!
notesprompt: String!
pillar: Pillar!
}

type Pillar {
pillarid: ID!
pillar: String!
}

interface Response {
Expand Down
4 changes: 2 additions & 2 deletions backend/cmd/api/internal/model/fismasystems.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (f *FismaSystem) FunctionScores(ctx context.Context) ([]*FunctionScore, err

return pgx.CollectRows(rows, func(row pgx.CollectableRow) (*FunctionScore, error) {
functionScore := FunctionScore{}
err := rows.Scan(&functionScore.Scoreid, &functionScore.Fismasystemid, &functionScore.Functionid, &functionScore.Datecalculated, &functionScore.Score, &functionScore.Notes)
err := row.Scan(&functionScore.Scoreid, &functionScore.Fismasystemid, &functionScore.Functionid, &functionScore.Datecalculated, &functionScore.Score, &functionScore.Notes)
return &functionScore, err

})
Expand Down Expand Up @@ -69,7 +69,7 @@ func FindFismaSystems(ctx context.Context, input FindFismaSystemsInput) ([]*Fism

return pgx.CollectRows(rows, func(row pgx.CollectableRow) (*FismaSystem, error) {
fismaSystem := FismaSystem{}
err := rows.Scan(&fismaSystem.Fismasystemid, &fismaSystem.Fismauid, &fismaSystem.Fismaacronym, &fismaSystem.Fismaname, &fismaSystem.Fismasubsystem, &fismaSystem.Component, &fismaSystem.Groupacronym, &fismaSystem.Groupname, &fismaSystem.Divisionname, &fismaSystem.Datacenterenvironment, &fismaSystem.Datacallcontact, &fismaSystem.Issoemail)
err := row.Scan(&fismaSystem.Fismasystemid, &fismaSystem.Fismauid, &fismaSystem.Fismaacronym, &fismaSystem.Fismaname, &fismaSystem.Fismasubsystem, &fismaSystem.Component, &fismaSystem.Groupacronym, &fismaSystem.Groupname, &fismaSystem.Divisionname, &fismaSystem.Datacenterenvironment, &fismaSystem.Datacallcontact, &fismaSystem.Issoemail)
return &fismaSystem, err
})
}
Expand Down
11 changes: 11 additions & 0 deletions backend/cmd/api/internal/model/functionoptions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package model

import "github.com/graph-gophers/graphql-go"

type FunctionOption struct {
Functionoptionid graphql.ID
Functionid int32
Score int32
Optionname string
Description string
}
41 changes: 35 additions & 6 deletions backend/cmd/api/internal/model/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@ type Function struct {
Pillar *string
Name *string
Description *string
Traditional *string
Initial *string
Advanced *string
Optimal *string
Datacenterenvironment *string
Questionid *int32
}

func FindFunctions(ctx context.Context) ([]*Function, error) {
Expand All @@ -28,8 +25,9 @@ func FindFunctions(ctx context.Context) ([]*Function, error) {
}

return pgx.CollectRows(rows, func(row pgx.CollectableRow) (*Function, error) {
log.Printf("%+v\n", row)
function := Function{}
err := rows.Scan(&function.Functionid, &function.Pillar, &function.Name, &function.Description, &function.Traditional, &function.Initial, &function.Advanced, &function.Optimal, &function.Datacenterenvironment)
err := row.Scan(&function.Functionid, &function.Pillar, &function.Name, &function.Description, &function.Datacenterenvironment)
return &function, err
})
}
Expand All @@ -42,11 +40,42 @@ func FindFunctionById(ctx context.Context, functionid graphql.ID) (*Function, er
}

function := Function{}
err = row.Scan(&function.Functionid, &function.Pillar, &function.Name, &function.Description, &function.Traditional, &function.Initial, &function.Advanced, &function.Optimal, &function.Datacenterenvironment)
err = row.Scan(&function.Functionid, &function.Pillar, &function.Name, &function.Description, &function.Datacenterenvironment)
if err != nil {
log.Println(err)
return nil, err
}

return &function, nil
}

func (f *Function) Options(ctx context.Context) ([]*FunctionOption, error) {
sql := "SELECT functionoptionid, functionid, score, optionname, description FROM public.functionoptions WHERE functionid=$1 ORDER BY score ASC"
rows, err := query(ctx, sql, f.Functionid)
if err != nil {
log.Println(err)
return nil, err
}
return pgx.CollectRows(rows, func(row pgx.CollectableRow) (*FunctionOption, error) {
functionOption := FunctionOption{}
err := row.Scan(&functionOption.Functionoptionid, &functionOption.Functionid, &functionOption.Score, &functionOption.Optionname, &functionOption.Description)
return &functionOption, err
})
}

func (f *Function) Question(ctx context.Context) (*Question, error) {
row, err := queryRow(ctx, "SELECT * FROM questions WHERE questionid=$1", f.Questionid)
if err != nil {
log.Println(err)
return nil, err
}

question := Question{}
err = row.Scan(&question.Questionid, &question.Question, &question.Notesprompt)
if err != nil {
log.Println(err)
return nil, err
}

return &question, nil
}
2 changes: 1 addition & 1 deletion backend/cmd/api/internal/model/functionscores.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (f *FunctionScore) Function(ctx context.Context) (*Function, error) {
}

function := Function{}
err = row.Scan(&function.Functionid, &function.Pillar, &function.Name, &function.Description, &function.Traditional, &function.Initial, &function.Advanced, &function.Optimal, &function.Datacenterenvironment)
err = row.Scan(&function.Functionid, &function.Pillar, &function.Name, &function.Description, &function.Datacenterenvironment)
if err != nil {
log.Print(err)
return nil, err
Expand Down
9 changes: 9 additions & 0 deletions backend/cmd/api/internal/model/questions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package model

import "github.com/graph-gophers/graphql-go"

type Question struct {
Questionid graphql.ID
Question string
Notesprompt string
}
2 changes: 1 addition & 1 deletion backend/cmd/api/internal/model/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func FindUsers(ctx context.Context) ([]*User, error) {

return pgx.CollectRows(rows, func(row pgx.CollectableRow) (*User, error) {
user := User{}
err := rows.Scan(&user.Userid, &user.Email, &user.Fullname, &user.Role)
err := row.Scan(&user.Userid, &user.Email, &user.Fullname, &user.Role)
return &user, err
})
}
Expand Down
41 changes: 34 additions & 7 deletions backend/db-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,43 @@ CREATE TABLE IF NOT EXISTS public.fismasystems

CREATE TABLE public.functions (
functionid SERIAL PRIMARY KEY,
pillar varchar(255),
function varchar(255),
description varchar(1024),
traditional varchar(1024),
initial varchar(1024),
advanced varchar(1024),
optimal varchar(1024),
datacenterenvironment varchar(255)
datacenterenvironment varchar(255),
questionid INT NOT NULL,
pillarid INT NOT NULL
) TABLESPACE pg_default;

CREATE TABLE public.functionoptions (
functionoptionid SERIAL PRIMARY KEY,
functionid INT REFERENCES functions (functionid) NOT NULL,
score INT NOT NULL,
optionname varchar(30) NOT NULL,
description varchar(1024)
);

CREATE TABLE public.functionscores (
scoreid SERIAL PRIMARY KEY,
fismasystemid INT NOT NULL,
functionid INT NOT NULL,
functionoptionid INT,
datecalculated TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
score FLOAT NOT NULL,
score INT NOT NULL,
notes varchar(1000)
) TABLESPACE pg_default;

CREATE TABLE public.questions (
questionid SERIAL PRIMARY KEY,
question varchar(1000) NOT NULL,
notesprompt varchar(1000) NOT NULL,
pillarid INT NOT NULL,
)

CREATE TABLE public.pillars (
pillarid SERIAL PRIMARY KEY,
pillar varchar(100)
)

CREATE TYPE roles AS ENUM ('ISSO','ISSM','ADMIN');

CREATE TABLE public.users (
Expand All @@ -50,3 +68,12 @@ CREATE TABLE public.users_fismasystems (
fismasystemid INT REFERENCES fismasystems (fismasystemid) ON DELETE CASCADE,
PRIMARY KEY (userid, fismasystemid)
)

-- VIEWS --

CREATE VIEW public.functions_with_options
AS
SELECT functions.*, json_agg(json_build_object('functionoptionid', functionoptionid, 'score', score, 'optionname', optionname, 'description', functionoptions.description)) as options from functions
LEFT JOIN functionoptions ON functionoptions.functionid=functions.functionid
GROUP BY functions.functionid
;
Loading