Adding group creation support.

This commit is contained in:
sergiotarxz 2021-02-10 00:59:49 +01:00
parent b0e9e7c35c
commit cc509ec22a
Signed by: sergiotarxz
GPG Key ID: E5903508B6510AC2
4 changed files with 430 additions and 1 deletions

View File

@ -0,0 +1,177 @@
package groupcontroller
import (
d "WWWShop/wwwshop/dao/database"
u "WWWShop/wwwshop/dao/groupmanager"
"WWWShop/wwwshop/model/group"
"bytes"
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"
"errors"
)
type GroupController struct{}
func New() GroupController {
return GroupController{}
}
func (self GroupController) DELETE(w http.ResponseWriter, r *http.Request) {
ids, groupnames, _, err := self.SetupInputForFilter(w, r)
group_manager := u.New(d.DB())
if err != nil {
if err != nil {
json_response,_ := EncodeJSONResponse(NewResponseError(err.Error()))
fmt.Fprintf(w, json_response)
return
}
}
deleted_groups, err := group_manager.Delete(ids, groupnames)
if err != nil {
json_response, _ := EncodeJSONResponse(NewResponseError(err.Error()))
fmt.Fprintf(w, json_response)
return
}
deleted_groups_json, _ := EncodeJSONResponse(deleted_groups)
fmt.Fprintf(w, deleted_groups_json)
}
func (self GroupController) SetupInputForFilter(w http.ResponseWriter, r *http.Request) ([]int64, []string, *int64, error) {
query := r.URL.Query()
groupnames, _ := query["groupname"]
ids, _ := query["id"]
pages, _ := query["page"]
var page int64
if len(pages) == 0 {
page = 0
} else {
var err error
page, err = strconv.ParseInt(pages[0], 0, 64)
if err != nil {
return nil, nil, nil, errors.New("Unable to parse int page.")
}
}
ids_int := make([]int64, 0)
for _, id := range ids {
id_int, err := strconv.ParseInt(id, 0, 64)
if err != nil {
return nil, nil, nil, errors.New("Unable to parse int id.")
}
ids_int = append(ids_int, id_int)
}
return ids_int, groupnames, &page, nil
}
func (self GroupController) PUT(w http.ResponseWriter, r *http.Request) {
var decoded_group_struct group.Group
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&decoded_group_struct)
if err != nil {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
json_response, _ := EncodeJSONResponse(NewResponseError("Failed to decode json group on update."))
fmt.Fprintf(w, json_response)
return
}
if decoded_group_struct.Id == nil && decoded_group_struct.Groupname == nil {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
json_response, _ := EncodeJSONResponse(NewResponseError("Failed to get groupname or id needed to update groups."))
fmt.Fprintf(w, json_response)
return
}
if decoded_group_struct.Permissions == nil {
decoded_group_struct.Permissions = make(map[string]string)
}
group_manager := u.New(d.DB())
group, err := group_manager.Update(decoded_group_struct)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
json_response, _ := EncodeJSONResponse(NewResponseError(strings.Join([]string{"Failed to update group with the given data, may be our fault: ", err.Error()}, "")))
fmt.Fprintf(w, json_response)
return
}
json_response, _ := EncodeJSONResponse(group)
fmt.Fprintf(w, json_response)
}
func (self GroupController) GET(w http.ResponseWriter, r *http.Request) {
group_manager := u.New(d.DB())
ids, groupnames, page, err := self.SetupInputForFilter(w, r)
if err != nil {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
json_response, _ := EncodeJSONResponse(NewResponseError(err.Error()))
fmt.Fprintf(w, json_response)
return
}
groups, err := group_manager.Retrieve(*page, ids, groupnames)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
json_response, _ := EncodeJSONResponse(NewResponseError(strings.Join([]string{"Unable to retrieve groups ", err.Error()}, "")))
fmt.Fprintf(w, json_response)
return
}
json_response, _ := EncodeJSONResponse(groups)
fmt.Fprintf(w, json_response)
}
func (self GroupController) POST(w http.ResponseWriter, r *http.Request) {
var decoded_group_struct POSTGroup
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&decoded_group_struct)
if err != nil {
json_response, _ := EncodeJSONResponse(NewResponseError("Unable to decode json"))
fmt.Fprintf(w, json_response)
return
}
if decoded_group_struct.Groupname == "" {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
json_response, _ := EncodeJSONResponse(NewResponseError("Unable to get groupname"))
fmt.Fprintf(w, json_response)
return
}
if decoded_group_struct.Permissions == nil {
decoded_group_struct.Permissions = make(map[string]string)
}
group_manager := u.New(d.DB())
group, err := group_manager.Add(decoded_group_struct.Groupname, decoded_group_struct.Permissions)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
json_response, _ := EncodeJSONResponse(NewResponseError(strings.Join(
[]string{"Unable to create group ", err.Error()},
"")))
fmt.Fprintf(w, json_response)
return
}
json_response, err := EncodeJSONResponse(group)
fmt.Fprintf(w, json_response)
}
type Response interface{}
type ResponseError struct {
Error string `json:"error"`
}
func NewResponseError(error_str string) ResponseError {
return ResponseError{
Error: error_str,
}
}
type POSTGroup struct {
Groupname string `json:"groupname"`
Permissions map[string]string `json:"permissions"`
}
func EncodeJSONResponse(response Response) (string, error) {
var buffer bytes.Buffer
encoder := json.NewEncoder(&buffer)
err := encoder.Encode(response)
if err != nil {
return "", err
}
return buffer.String(), nil
}

View File

@ -0,0 +1,217 @@
package groupmanager
import (
"WWWShop/wwwshop/model/group"
"database/sql"
"errors"
"fmt"
"github.com/lib/pq/hstore"
"log"
"strings"
)
type GroupManager struct {
db *sql.DB
}
func New(db *sql.DB) GroupManager {
return GroupManager{db}
}
func (self GroupManager) Add(groupname string, permissions map[string]string) (*group.Group, error) {
var id int64
if permissions == nil {
permissions = make(map[string]string)
}
permissions_null := hstore.Hstore{
Map: make(map[string]sql.NullString),
}
for key, value := range permissions {
permissions_null.Map[key] = sql.NullString{
String: value,
Valid: true,
}
}
result := self.db.QueryRow("INSERT INTO groups(groupname, permissions) VALUES ($1, $2) RETURNING id", groupname, permissions_null)
err := result.Scan(&id)
if err != nil {
return nil, err
}
group := group.New(id, groupname, permissions)
return &group, nil
}
type QueryParameter interface{}
func (self GroupManager) GenerateWhere(cur_key *int64, ids []int64, groupnames []string) string {
where_string := "WHERE false "
if groupnames != nil && len(groupnames) > 0 {
where_string = strings.Join([]string{where_string, "OR ( false"}, "")
for range groupnames {
where_string = strings.Join([]string{where_string, fmt.Sprintf(" OR groupname = $%d", *cur_key)}, "")
(*cur_key)++
}
where_string = strings.Join([]string{where_string, " ) "}, "")
}
if ids != nil && len(ids) > 0 {
where_string = strings.Join([]string{where_string, "OR ( false"}, "")
for range ids {
where_string = strings.Join([]string{where_string, fmt.Sprintf(" OR id = $%d", *cur_key)}, "")
(*cur_key)++
}
where_string = strings.Join([]string{where_string, " ) "}, "")
}
return where_string
}
func (self GroupManager) Update(group group.Group) (*group.Group, error) {
if group.Id == nil && group.Groupname == nil {
return nil, errors.New("Both Id and Groupname cannot be null on the same time on UPDATE.")
}
if group.Permissions == nil {
return nil, errors.New("Should be at least a field for update .")
}
query := "UPDATE groups SET permissions = $1 WHERE true "
parameters := make([]interface{}, 0)
permissions_null := hstore.Hstore{
Map: make(map[string]sql.NullString),
}
for key, value := range group.Permissions {
log.Println(value)
permissions_null.Map[key] = sql.NullString{
String: value,
Valid: true,
}
}
parameters = append(parameters, permissions_null)
if group.Id != nil {
query = strings.Join([]string{query, "AND id = $2 "}, "")
parameters = append(parameters, *(group.Id))
} else {
query = strings.Join([]string{query, "AND groupname = $2 "}, "")
parameters = append(parameters, *(group.Groupname))
}
query = strings.Join([]string{query, " RETURNING id"}, "")
var id int64
result := self.db.QueryRow(query, parameters...)
err := result.Scan(&id)
if err != nil {
return nil, err
}
groups, err := self.Retrieve(0, []int64{id}, nil)
group = groups[0]
if err != nil {
return nil, err
}
return &group, nil
}
func (self GroupManager) Delete(ids []int64, groupnames []string) ([]string, error) {
var where bool
var cur_key int64
var where_string string
cur_key = 1
if ids != nil && len(ids) > 0 {
where = true
}
if groupnames != nil && len(groupnames) > 0 {
where = true
}
if where {
where_string = self.GenerateWhere(&cur_key, ids, groupnames)
} else {
return nil, errors.New("Cannot delete without a clause")
}
query_parameters := make([]interface{}, 0)
for _, groupname := range groupnames {
query_parameters = append(query_parameters, groupname)
}
for _, id := range ids {
query_parameters = append(query_parameters, id)
}
query_string := fmt.Sprintf("DELETE FROM groups %s RETURNING groupname", where_string)
result, err := self.db.Query(
query_string,
query_parameters...,
)
if err != nil {
return nil, err
}
defer result.Close()
var deleted_groups []string
for result.Next() {
var groupname string
err := result.Scan(&groupname)
if err != nil {
return nil, err
}
deleted_groups = append(deleted_groups, groupname)
}
if deleted_groups == nil {
deleted_groups = make([]string, 0)
}
return deleted_groups, nil
}
func (self GroupManager) Retrieve(page int64, ids []int64, groupnames []string) ([]group.Group, error) {
var where bool
var cur_key int64
if ids != nil && len(ids) > 0 {
where = true
}
if groupnames != nil && len(groupnames) > 0 {
where = true
}
cur_key = 1
where_string := ""
if where {
where_string = self.GenerateWhere(&cur_key, ids, groupnames)
}
page = (10 * page)
page_string := fmt.Sprintf("LIMIT 10 OFFSET %d", page)
query_parameters := make([]interface{}, 0)
for _, groupname := range groupnames {
query_parameters = append(query_parameters, groupname)
}
for _, id := range ids {
query_parameters = append(query_parameters, id)
}
query_string := fmt.Sprintf("SELECT id, groupname, permissions from groups %s %s;", where_string, page_string)
result, err := self.db.Query(
query_string,
query_parameters...,
)
if err != nil {
return nil, err
}
defer result.Close()
var groups []group.Group
for result.Next() {
var (
id_group int64
groupname_group string
permissions_group_null hstore.Hstore
)
err := result.Scan(&id_group, &groupname_group, &permissions_group_null)
permissions_group := make(map[string]string)
for key, permission_null := range permissions_group_null.Map {
if permission_null.Valid {
permissions_group[key] = permission_null.String
}
}
if err != nil {
return nil, err
}
u := group.New(id_group, groupname_group, permissions_group)
groups = append(groups, u)
}
if groups == nil {
groups = make([]group.Group, 0)
}
return groups, nil
}

View File

@ -0,0 +1,33 @@
package group
import (
"log"
)
type Group struct {
Id *int64 `json:"id"`
Groupname *string `json:"groupname"`
Permissions map[string]string `json:"permissions"`
}
func New(id int64, groupname string, permissions map[string]string) Group {
return Group{
Id: &id,
Groupname: &groupname,
Permissions: permissions,
}
}
func (self Group) HasPermission(permission string) string {
perm_value, ok := self.Permissions[permission]
if ok {
if perm_value == "yes" {
return "yes"
}
if perm_value == "no" {
return "no"
}
log.Printf("Invalid permission value for %s in group %s.\n", permission, self.Groupname)
}
return ""
}

View File

@ -4,6 +4,7 @@ import (
"net/http"
c "WWWShop/wwwshop/controller"
u "WWWShop/wwwshop/controller/usercontroller"
g "WWWShop/wwwshop/controller/groupcontroller"
d "WWWShop/wwwshop/dao/database"
)
@ -18,7 +19,8 @@ func New() WWWShop {
func (self WWWShop) Init() {
d.Migrate(d.DB())
user_controller := c.GenerateController(u.New())
group_controller := c.GenerateController(g.New())
http.Handle("/group", group_controller)
http.Handle("/user", user_controller)
http.Handle("/user/", user_controller)
http.ListenAndServe(":8080", nil)
}