chore: some more clean up
This commit is contained in:
parent
fbf7eb9271
commit
8b13afba48
@ -2,7 +2,6 @@ package dbtypes
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserType int
|
type UserType int
|
||||||
@ -14,34 +13,20 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Id string
|
Id string `db:"u.id"`
|
||||||
Username string
|
Username string `db:"u.username"`
|
||||||
Email string
|
Email string `db:"u.email"`
|
||||||
UserType int
|
UserType int `db:"u.user_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrUserNotFound = errors.New("User Not found")
|
|
||||||
|
|
||||||
func UserFromToken(db *sql.DB, token string) (*User, error) {
|
func UserFromToken(db *sql.DB, token string) (*User, error) {
|
||||||
rows, err := db.Query("select users.id, users.username, users.email, users.user_type from users inner join tokens on tokens.user_id = users.id where tokens.token = $1;", token)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
var id string
|
var user User
|
||||||
var username string
|
|
||||||
var email string
|
|
||||||
var user_type int
|
|
||||||
|
|
||||||
if !rows.Next() {
|
err := GetDBOnce(db, &user, "users as u inner join tokens as t on t.user_id = u.id where t.token = $1;", token)
|
||||||
return nil, ErrUserNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
err = rows.Scan(&id, &username, &email, &user_type)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &User{id, username, email, user_type}, nil
|
return &user, nil
|
||||||
}
|
}
|
||||||
|
347
logic/db_types/utils.go
Normal file
347
logic/db_types/utils.go
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
package dbtypes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/log"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BasePack interface {
|
||||||
|
GetDb() *sql.DB
|
||||||
|
GetLogger() *log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type BasePackStruct struct {
|
||||||
|
Db *sql.DB
|
||||||
|
Logger *log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BasePackStruct) GetDb() *sql.DB {
|
||||||
|
return b.Db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BasePackStruct) GetLogger() *log.Logger {
|
||||||
|
return b.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckEmpty(f url.Values, path string) bool {
|
||||||
|
return !f.Has(path) || f.Get(path) == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckNumber(f url.Values, path string, number *int) bool {
|
||||||
|
if CheckEmpty(f, path) {
|
||||||
|
fmt.Println("here", path)
|
||||||
|
fmt.Println(f.Get(path))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(f.Get(path))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*number = n
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckFloat64(f url.Values, path string, number *float64) bool {
|
||||||
|
if CheckEmpty(f, path) {
|
||||||
|
fmt.Println("here", path)
|
||||||
|
fmt.Println(f.Get(path))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
n, err := strconv.ParseFloat(f.Get(path), 64)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*number = n
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckId(f url.Values, path string) bool {
|
||||||
|
return !CheckEmpty(f, path) && IsValidUUID(f.Get(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsValidUUID(u string) bool {
|
||||||
|
_, err := uuid.Parse(u)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type maxBytesReader struct {
|
||||||
|
w http.ResponseWriter
|
||||||
|
r io.ReadCloser // underlying reader
|
||||||
|
i int64 // max bytes initially, for MaxBytesError
|
||||||
|
n int64 // max bytes remaining
|
||||||
|
err error // sticky error
|
||||||
|
}
|
||||||
|
|
||||||
|
type MaxBytesError struct {
|
||||||
|
Limit int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *MaxBytesError) Error() string {
|
||||||
|
// Due to Hyrum's law, this text cannot be changed.
|
||||||
|
return "http: request body too large"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *maxBytesReader) Read(p []byte) (n int, err error) {
|
||||||
|
if l.err != nil {
|
||||||
|
return 0, l.err
|
||||||
|
}
|
||||||
|
if len(p) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
// If they asked for a 32KB byte read but only 5 bytes are
|
||||||
|
// remaining, no need to read 32KB. 6 bytes will answer the
|
||||||
|
// question of the whether we hit the limit or go past it.
|
||||||
|
// 0 < len(p) < 2^63
|
||||||
|
if int64(len(p))-1 > l.n {
|
||||||
|
p = p[:l.n+1]
|
||||||
|
}
|
||||||
|
n, err = l.r.Read(p)
|
||||||
|
|
||||||
|
if int64(n) <= l.n {
|
||||||
|
l.n -= int64(n)
|
||||||
|
l.err = err
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n = int(l.n)
|
||||||
|
l.n = 0
|
||||||
|
|
||||||
|
// The server code and client code both use
|
||||||
|
// maxBytesReader. This "requestTooLarge" check is
|
||||||
|
// only used by the server code. To prevent binaries
|
||||||
|
// which only using the HTTP Client code (such as
|
||||||
|
// cmd/go) from also linking in the HTTP server, don't
|
||||||
|
// use a static type assertion to the server
|
||||||
|
// "*response" type. Check this interface instead:
|
||||||
|
type requestTooLarger interface {
|
||||||
|
requestTooLarge()
|
||||||
|
}
|
||||||
|
if res, ok := l.w.(requestTooLarger); ok {
|
||||||
|
res.requestTooLarge()
|
||||||
|
}
|
||||||
|
l.err = &MaxBytesError{l.i}
|
||||||
|
return n, l.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *maxBytesReader) Close() error {
|
||||||
|
return l.r.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func MyParseForm(r *http.Request) (vs url.Values, err error) {
|
||||||
|
if r.Body == nil {
|
||||||
|
err = errors.New("missing form body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ct := r.Header.Get("Content-Type")
|
||||||
|
// RFC 7231, section 3.1.1.5 - empty type
|
||||||
|
// MAY be treated as application/octet-stream
|
||||||
|
if ct == "" {
|
||||||
|
ct = "application/octet-stream"
|
||||||
|
}
|
||||||
|
ct, _, err = mime.ParseMediaType(ct)
|
||||||
|
switch {
|
||||||
|
case ct == "application/x-www-form-urlencoded":
|
||||||
|
var reader io.Reader = r.Body
|
||||||
|
maxFormSize := int64(1<<63 - 1)
|
||||||
|
if _, ok := r.Body.(*maxBytesReader); !ok {
|
||||||
|
maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
|
||||||
|
reader = io.LimitReader(r.Body, maxFormSize+1)
|
||||||
|
}
|
||||||
|
b, e := io.ReadAll(reader)
|
||||||
|
if e != nil {
|
||||||
|
if err == nil {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if int64(len(b)) > maxFormSize {
|
||||||
|
err = errors.New("http: POST too large")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vs, e = url.ParseQuery(string(b))
|
||||||
|
if err == nil {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
case ct == "multipart/form-data":
|
||||||
|
// handled by ParseMultipartForm (which is calling us, or should be)
|
||||||
|
// TODO(bradfitz): there are too many possible
|
||||||
|
// orders to call too many functions here.
|
||||||
|
// Clean this up and write more tests.
|
||||||
|
// request_test.go contains the start of this,
|
||||||
|
// in TestParseMultipartFormOrder and others.
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type JustId struct {
|
||||||
|
Id string `json:"id" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Generic struct{ reflect.Type }
|
||||||
|
|
||||||
|
var NotFoundError = errors.New("Not found")
|
||||||
|
var CouldNotInsert = errors.New("Could not insert")
|
||||||
|
|
||||||
|
func generateQuery(t reflect.Type) (query string, nargs int) {
|
||||||
|
nargs = t.NumField()
|
||||||
|
query = ""
|
||||||
|
|
||||||
|
for i := 0; i < nargs; i += 1 {
|
||||||
|
field := t.Field(i)
|
||||||
|
name, ok := field.Tag.Lookup("db")
|
||||||
|
if !ok {
|
||||||
|
name = field.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == "__nil__" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
query += strings.ToLower(name) + ","
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the last comma
|
||||||
|
query = query[0 : len(query)-1]
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueryInterface interface {
|
||||||
|
Prepare(str string) (*sql.Stmt, error)
|
||||||
|
Query(query string, args ...any) (*sql.Rows, error)
|
||||||
|
Exec(query string, args ...any) (sql.Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDbMultitple[T interface{}](c QueryInterface, tablename string, args ...any) ([]*T, error) {
|
||||||
|
t := reflect.TypeFor[T]()
|
||||||
|
|
||||||
|
query, nargs := generateQuery(t)
|
||||||
|
|
||||||
|
db_query, err := c.Prepare(fmt.Sprintf("select %s from %s", query, tablename))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer db_query.Close()
|
||||||
|
|
||||||
|
rows, err := db_query.Query(args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
list := []*T{}
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
item := new(T)
|
||||||
|
if err = mapRow(item, rows, nargs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
list = append(list, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapRow(store interface{}, rows *sql.Rows, nargs int) (err error) {
|
||||||
|
err = nil
|
||||||
|
|
||||||
|
val := reflect.Indirect(reflect.ValueOf(store))
|
||||||
|
scan_args := make([]interface{}, nargs)
|
||||||
|
for i := 0; i < nargs; i++ {
|
||||||
|
valueField := val.Field(i)
|
||||||
|
scan_args[i] = valueField.Addr().Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rows.Scan(scan_args...)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertReturnId(c QueryInterface, store interface{}, tablename string, returnName string) (id string, err error) {
|
||||||
|
t := reflect.TypeOf(store).Elem()
|
||||||
|
|
||||||
|
query, nargs := generateQuery(t)
|
||||||
|
|
||||||
|
query2 := ""
|
||||||
|
for i := 0; i < nargs; i += 1 {
|
||||||
|
query2 += fmt.Sprintf("$%d,", i+1)
|
||||||
|
}
|
||||||
|
// Remove last quotation
|
||||||
|
query2 = query2[0 : len(query2)-1]
|
||||||
|
|
||||||
|
val := reflect.ValueOf(store).Elem()
|
||||||
|
scan_args := make([]interface{}, nargs)
|
||||||
|
for i := 0; i < nargs; i++ {
|
||||||
|
valueField := val.Field(i)
|
||||||
|
scan_args[i] = valueField.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := c.Query(fmt.Sprintf("insert into %s (%s) values (%s) returning %s", tablename, query, query2, returnName), scan_args...)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
if !rows.Next() {
|
||||||
|
return "", CouldNotInsert
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rows.Scan(&id)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDBOnce(db QueryInterface, store interface{}, tablename string, args ...any) error {
|
||||||
|
t := reflect.TypeOf(store).Elem()
|
||||||
|
|
||||||
|
query, nargs := generateQuery(t)
|
||||||
|
|
||||||
|
rows, err := db.Query(fmt.Sprintf("select %s from %s", query, tablename), args...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
if !rows.Next() {
|
||||||
|
return NotFoundError
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nil
|
||||||
|
|
||||||
|
val := reflect.ValueOf(store).Elem()
|
||||||
|
scan_args := make([]interface{}, nargs)
|
||||||
|
for i := 0; i < nargs; i++ {
|
||||||
|
valueField := val.Field(i)
|
||||||
|
scan_args[i] = valueField.Addr().Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rows.Scan(scan_args...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateStatus(c QueryInterface, table string, id string, status int) (err error) {
|
||||||
|
_, err = c.Exec(fmt.Sprintf("update %s set status = $1 where id = $2", table), status, id)
|
||||||
|
return
|
||||||
|
}
|
@ -3,7 +3,7 @@ package model_classes
|
|||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ func HandleList(handle *Handle) {
|
|||||||
Model_id string
|
Model_id string
|
||||||
}
|
}
|
||||||
|
|
||||||
err = utils.GetDBOnce(c, &class_row, "model_classes where id=$1", id)
|
err = GetDBOnce(c, &class_row, "model_classes where id=$1", id)
|
||||||
if err == NotFoundError {
|
if err == NotFoundError {
|
||||||
return c.JsonBadRequest("Model Class not found!")
|
return c.JsonBadRequest("Model Class not found!")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -47,7 +47,7 @@ func HandleList(handle *Handle) {
|
|||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := utils.GetDbMultitple[baserow](c, "model_data_point where class_id=$1 limit 11 offset $2", id, page*10)
|
rows, err := GetDbMultitple[baserow](c, "model_data_point where class_id=$1 limit 11 offset $2", id, page*10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Error500(err)
|
return c.Error500(err)
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ func HandleList(handle *Handle) {
|
|||||||
|
|
||||||
max_len := min(11, len(rows))
|
max_len := min(11, len(rows))
|
||||||
|
|
||||||
c.ShowMessage = false;
|
c.ShowMessage = false
|
||||||
return c.SendJSON(ReturnType{
|
return c.SendJSON(ReturnType{
|
||||||
ImageList: rows[0:max_len],
|
ImageList: rows[0:max_len],
|
||||||
Page: page,
|
Page: page,
|
||||||
|
@ -4,7 +4,8 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ModelClass struct {
|
type ModelClass struct {
|
||||||
@ -15,7 +16,7 @@ type ModelClass struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ListClasses(c *Context, model_id string) (cls []*ModelClass, err error) {
|
func ListClasses(c *Context, model_id string) (cls []*ModelClass, err error) {
|
||||||
return GetDbMultitple[ModelClass](c, "model_classes where model_id=$1", model_id)
|
return GetDbMultitple[ModelClass](c, "model_classes where model_id=$1", model_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ModelHasDataPoints(db *sql.DB, model_id string) (result bool, err error) {
|
func ModelHasDataPoints(db *sql.DB, model_id string) (result bool, err error) {
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
model_classes "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/classes"
|
model_classes "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/classes"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
|
@ -5,9 +5,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
utils "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func deleteModelJSON(c *Context, id string) *Error {
|
func deleteModelJSON(c *Context, id string) *Error {
|
||||||
@ -47,7 +47,7 @@ func handleDelete(handle *Handle) {
|
|||||||
Status int
|
Status int
|
||||||
}
|
}
|
||||||
|
|
||||||
err := utils.GetDBOnce(c, &model, "models where id=$1 and user_id=$2;", dat.Id, c.User.Id)
|
err := GetDBOnce(c, &model, "models where id=$1 and user_id=$2;", dat.Id, c.User.Id)
|
||||||
if err == NotFoundError {
|
if err == NotFoundError {
|
||||||
return c.SendJSONStatus(http.StatusNotFound, "Model not found!")
|
return c.SendJSONStatus(http.StatusNotFound, "Model not found!")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -3,9 +3,9 @@ package models
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
model_classes "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/classes"
|
model_classes "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/classes"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
||||||
"git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,10 +15,10 @@ func handleEdit(handle *Handle) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
model, err_ := c.GetModelFromId("id")
|
model, err_ := c.GetModelFromId("id")
|
||||||
if err_ != nil {
|
if err_ != nil {
|
||||||
return err_
|
return err_
|
||||||
}
|
}
|
||||||
|
|
||||||
wrong_number, err := model_classes.GetNumberOfWrongDataPoints(c.Db, model.Id)
|
wrong_number, err := model_classes.GetNumberOfWrongDataPoints(c.Db, model.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -41,7 +41,7 @@ func handleEdit(handle *Handle) {
|
|||||||
NumberOfInvalidImages int `json:"number_of_invalid_images"`
|
NumberOfInvalidImages int `json:"number_of_invalid_images"`
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ShowMessage = false;
|
c.ShowMessage = false
|
||||||
return c.SendJSON(ReturnType{
|
return c.SendJSON(ReturnType{
|
||||||
Classes: cls,
|
Classes: cls,
|
||||||
HasData: has_data,
|
HasData: has_data,
|
||||||
@ -54,10 +54,10 @@ func handleEdit(handle *Handle) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
model, err_ := c.GetModelFromId("id")
|
model, err_ := c.GetModelFromId("id")
|
||||||
if err_ != nil {
|
if err_ != nil {
|
||||||
return err_
|
return err_
|
||||||
}
|
}
|
||||||
|
|
||||||
type defrow struct {
|
type defrow struct {
|
||||||
Id string
|
Id string
|
||||||
@ -180,8 +180,8 @@ func handleEdit(handle *Handle) {
|
|||||||
Layers: lay,
|
Layers: lay,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ShowMessage = false;
|
c.ShowMessage = false
|
||||||
return c.SendJSON(defsToReturn)
|
return c.SendJSON(defsToReturn)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -207,14 +207,14 @@ func handleEdit(handle *Handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var model rowmodel = rowmodel{}
|
var model rowmodel = rowmodel{}
|
||||||
err = utils.GetDBOnce(c, &model, "models where id=$1 and user_id=$2", id, c.User.Id)
|
err = GetDBOnce(c, &model, "models where id=$1 and user_id=$2", id, c.User.Id)
|
||||||
if err == NotFoundError {
|
if err == NotFoundError {
|
||||||
return c.SendJSONStatus(404, "Model not found")
|
return c.SendJSONStatus(404, "Model not found")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return c.Error500(err)
|
return c.Error500(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ShowMessage = false
|
c.ShowMessage = false
|
||||||
return c.SendJSON(model)
|
return c.SendJSON(model)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Auth level set when path is definied as 1
|
// Auth level set when path is definied as 1
|
||||||
func handleStats(c *Context) *Error {
|
func handleStats(c *Context) *Error {
|
||||||
var b struct {
|
var b struct {
|
||||||
Id string `json:"id" validate:"required"`
|
Id string `json:"id" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if _err := c.ToJSON(&b); _err != nil {
|
if _err := c.ToJSON(&b); _err != nil {
|
||||||
return _err;
|
return _err
|
||||||
}
|
}
|
||||||
|
|
||||||
type Row struct {
|
type Row struct {
|
||||||
Name string `db:"mc.name" json:"name"`
|
Name string `db:"mc.name" json:"name"`
|
||||||
Training string `db:"count(mdp.id) filter (where mdp.model_mode=1)" json:"training"`
|
Training string `db:"count(mdp.id) filter (where mdp.model_mode=1)" json:"training"`
|
||||||
Testing string `db:"count(mdp.id) filter (where mdp.model_mode=2)" json:"testing"`
|
Testing string `db:"count(mdp.id) filter (where mdp.model_mode=2)" json:"testing"`
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := GetDbMultitple[Row](c, "model_data_point as mdp inner join model_classes as mc on mc.id=mdp.class_id where mc.model_id=$1 group by mc.name order by mc.name asc;", b.Id)
|
rows, err := GetDbMultitple[Row](c, "model_data_point as mdp inner join model_classes as mc on mc.id=mdp.class_id where mc.model_id=$1 group by mc.name order by mc.name asc;", b.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Error500(err)
|
return c.Error500(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ShowMessage = false
|
c.ShowMessage = false
|
||||||
return c.SendJSON(rows)
|
return c.SendJSON(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,12 +41,12 @@ func handleList(handle *Handle) {
|
|||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
got, err := utils.GetDbMultitple[Row](c, "models where user_id=$1", c.User.Id)
|
got, err := GetDbMultitple[Row](c, "models where user_id=$1", c.User.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Error500(nil)
|
return c.Error500(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ShowMessage = true
|
c.ShowMessage = true
|
||||||
return c.SendJSON(got)
|
return c.SendJSON(got)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
|
||||||
|
|
||||||
tf "github.com/galeone/tensorflow/tensorflow/go"
|
tf "github.com/galeone/tensorflow/tensorflow/go"
|
||||||
"github.com/galeone/tensorflow/tensorflow/go/op"
|
"github.com/galeone/tensorflow/tensorflow/go/op"
|
||||||
@ -119,7 +119,7 @@ func runModelExp(base BasePack, model *BaseModel, def_id string, inputImage *tf.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ClassifyTask(base BasePack, task Task) (err error) {
|
func ClassifyTask(base BasePack, task Task) (err error) {
|
||||||
task.UpdateStatusLog(base, TASK_RUNNING, "Runner running task")
|
task.UpdateStatusLog(base, TASK_RUNNING, "Runner running task")
|
||||||
|
|
||||||
model, err := GetBaseModel(base.GetDb(), task.ModelId)
|
model, err := GetBaseModel(base.GetDb(), task.ModelId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -206,13 +206,13 @@ func ClassifyTask(base BasePack, task Task) (err error) {
|
|||||||
Confidence: confidence,
|
Confidence: confidence,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = task.SetResult(base, returnValue)
|
err = task.SetResult(base, returnValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
task.UpdateStatusLog(base, TASK_FAILED_RUNNING, "Failed to save model results")
|
task.UpdateStatusLog(base, TASK_FAILED_RUNNING, "Failed to save model results")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
task.UpdateStatusLog(base, TASK_DONE, "Model ran successfully")
|
task.UpdateStatusLog(base, TASK_DONE, "Model ran successfully")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
model_classes "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/classes"
|
model_classes "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/classes"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
@ -336,7 +337,7 @@ func generateCvsExpandExp(c *Context, run_path string, model_id string, offset i
|
|||||||
// This is to load some extra data so that the model has more things to train on
|
// This is to load some extra data so that the model has more things to train on
|
||||||
//
|
//
|
||||||
|
|
||||||
data_other, err := c.Db.Query("select mdp.id, mc.class_order, mdp.file_path from model_data_point as mdp inner join model_classes as mc on mc.id = mdp.class_id where mc.model_id = $1 and mdp.model_mode=$2 and mc.status=$3 limit $4;", model_id, model_classes.DATA_POINT_MODE_TRAINING, MODEL_CLASS_STATUS_TRAINED, count * 10)
|
data_other, err := c.Db.Query("select mdp.id, mc.class_order, mdp.file_path from model_data_point as mdp inner join model_classes as mc on mc.id = mdp.class_id where mc.model_id = $1 and mdp.model_mode=$2 and mc.status=$3 limit $4;", model_id, model_classes.DATA_POINT_MODE_TRAINING, MODEL_CLASS_STATUS_TRAINED, count*10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1905,7 +1906,7 @@ func handleTrain(handle *Handle) {
|
|||||||
return c.Error500(err)
|
return c.Error500(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ShowMessage = false
|
c.ShowMessage = false
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1955,7 +1956,7 @@ func handleTrain(handle *Handle) {
|
|||||||
return c.Error500(err)
|
return c.Error500(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ShowMessage = false
|
c.ShowMessage = false
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
||||||
@ -46,7 +47,7 @@ func handleUpload(handler *Handle) {
|
|||||||
var requestData struct {
|
var requestData struct {
|
||||||
ModelId string `json:"id" validate:"required"`
|
ModelId string `json:"id" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
_err := c.ParseJson(&requestData, json_data)
|
_err := c.ParseJson(&requestData, json_data)
|
||||||
if _err != nil {
|
if _err != nil {
|
||||||
return _err
|
return _err
|
||||||
@ -115,7 +116,7 @@ func handleUpload(handler *Handle) {
|
|||||||
Id string `json:"task_id"`
|
Id string `json:"task_id"`
|
||||||
} { "Provided image does not match the model", id})
|
} { "Provided image does not match the model", id})
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateStatus(c, "tasks", id, 1)
|
UpdateStatus(c, "tasks", id, 1)
|
||||||
|
|
||||||
return c.SendJSON(struct {Id string `json:"id"`}{id})
|
return c.SendJSON(struct {Id string `json:"id"`}{id})
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package tasks
|
package tasks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
dbtypes "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
dbtypes "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
||||||
|
@ -8,9 +8,10 @@ import (
|
|||||||
|
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
|
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,13 +37,13 @@ func runner(db *sql.DB, task_channel chan Task, index int, back_channel chan int
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
base := BasePackStruct{
|
base := BasePackStruct{
|
||||||
Db: db,
|
Db: db,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
for task := range task_channel {
|
for task := range task_channel {
|
||||||
logger.Info("Got task", "task", task)
|
logger.Info("Got task", "task", task)
|
||||||
|
|
||||||
if task.TaskType == int(TASK_TYPE_CLASSIFICATION) {
|
if task.TaskType == int(TASK_TYPE_CLASSIFICATION) {
|
||||||
logger.Info("Classification Task")
|
logger.Info("Classification Task")
|
||||||
if err = ClassifyTask(base, task); err != nil {
|
if err = ClassifyTask(base, task); err != nil {
|
||||||
@ -80,7 +81,7 @@ func attentionSeeker(config Config, back_channel chan int) {
|
|||||||
|
|
||||||
for true {
|
for true {
|
||||||
back_channel <- 0
|
back_channel <- 0
|
||||||
|
|
||||||
time.Sleep(t)
|
time.Sleep(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package tasks_utils
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
"github.com/goccy/go-json"
|
"github.com/goccy/go-json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -204,6 +204,10 @@ func (c Context) Query(query string, args ...any) (*sql.Rows, error) {
|
|||||||
return c.Db.Query(query, args...)
|
return c.Db.Query(query, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Context) Exec(query string, args ...any) (sql.Result, error) {
|
||||||
|
return c.Db.Exec(query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (c Context) Prepare(str string) (*sql.Stmt, error) {
|
func (c Context) Prepare(str string) (*sql.Stmt, error) {
|
||||||
if c.Tx == nil {
|
if c.Tx == nil {
|
||||||
return c.Db.Prepare(str)
|
return c.Db.Prepare(str)
|
||||||
|
@ -1,83 +1,11 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"mime"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/log"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type BasePack interface {
|
|
||||||
GetDb() *sql.DB
|
|
||||||
GetLogger() *log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type BasePackStruct struct {
|
|
||||||
Db *sql.DB
|
|
||||||
Logger *log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b BasePackStruct) GetDb() (*sql.DB) {
|
|
||||||
return b.Db
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b BasePackStruct) GetLogger() (*log.Logger) {
|
|
||||||
return b.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckEmpty(f url.Values, path string) bool {
|
|
||||||
return !f.Has(path) || f.Get(path) == ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckNumber(f url.Values, path string, number *int) bool {
|
|
||||||
if CheckEmpty(f, path) {
|
|
||||||
fmt.Println("here", path)
|
|
||||||
fmt.Println(f.Get(path))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
n, err := strconv.Atoi(f.Get(path))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
*number = n
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckFloat64(f url.Values, path string, number *float64) bool {
|
|
||||||
if CheckEmpty(f, path) {
|
|
||||||
fmt.Println("here", path)
|
|
||||||
fmt.Println(f.Get(path))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
n, err := strconv.ParseFloat(f.Get(path), 64)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
*number = n
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckId(f url.Values, path string) bool {
|
|
||||||
return !CheckEmpty(f, path) && IsValidUUID(f.Get(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsValidUUID(u string) bool {
|
|
||||||
_, err := uuid.Parse(u)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetIdFromUrl(c *Context, target string) (string, error) {
|
func GetIdFromUrl(c *Context, target string) (string, error) {
|
||||||
if !c.R.URL.Query().Has(target) {
|
if !c.R.URL.Query().Has(target) {
|
||||||
return "", errors.New("Query does not have " + target)
|
return "", errors.New("Query does not have " + target)
|
||||||
@ -94,269 +22,3 @@ func GetIdFromUrl(c *Context, target string) (string, error) {
|
|||||||
|
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type maxBytesReader struct {
|
|
||||||
w http.ResponseWriter
|
|
||||||
r io.ReadCloser // underlying reader
|
|
||||||
i int64 // max bytes initially, for MaxBytesError
|
|
||||||
n int64 // max bytes remaining
|
|
||||||
err error // sticky error
|
|
||||||
}
|
|
||||||
|
|
||||||
type MaxBytesError struct {
|
|
||||||
Limit int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *MaxBytesError) Error() string {
|
|
||||||
// Due to Hyrum's law, this text cannot be changed.
|
|
||||||
return "http: request body too large"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *maxBytesReader) Read(p []byte) (n int, err error) {
|
|
||||||
if l.err != nil {
|
|
||||||
return 0, l.err
|
|
||||||
}
|
|
||||||
if len(p) == 0 {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
// If they asked for a 32KB byte read but only 5 bytes are
|
|
||||||
// remaining, no need to read 32KB. 6 bytes will answer the
|
|
||||||
// question of the whether we hit the limit or go past it.
|
|
||||||
// 0 < len(p) < 2^63
|
|
||||||
if int64(len(p))-1 > l.n {
|
|
||||||
p = p[:l.n+1]
|
|
||||||
}
|
|
||||||
n, err = l.r.Read(p)
|
|
||||||
|
|
||||||
if int64(n) <= l.n {
|
|
||||||
l.n -= int64(n)
|
|
||||||
l.err = err
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
n = int(l.n)
|
|
||||||
l.n = 0
|
|
||||||
|
|
||||||
// The server code and client code both use
|
|
||||||
// maxBytesReader. This "requestTooLarge" check is
|
|
||||||
// only used by the server code. To prevent binaries
|
|
||||||
// which only using the HTTP Client code (such as
|
|
||||||
// cmd/go) from also linking in the HTTP server, don't
|
|
||||||
// use a static type assertion to the server
|
|
||||||
// "*response" type. Check this interface instead:
|
|
||||||
type requestTooLarger interface {
|
|
||||||
requestTooLarge()
|
|
||||||
}
|
|
||||||
if res, ok := l.w.(requestTooLarger); ok {
|
|
||||||
res.requestTooLarge()
|
|
||||||
}
|
|
||||||
l.err = &MaxBytesError{l.i}
|
|
||||||
return n, l.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *maxBytesReader) Close() error {
|
|
||||||
return l.r.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func MyParseForm(r *http.Request) (vs url.Values, err error) {
|
|
||||||
if r.Body == nil {
|
|
||||||
err = errors.New("missing form body")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ct := r.Header.Get("Content-Type")
|
|
||||||
// RFC 7231, section 3.1.1.5 - empty type
|
|
||||||
// MAY be treated as application/octet-stream
|
|
||||||
if ct == "" {
|
|
||||||
ct = "application/octet-stream"
|
|
||||||
}
|
|
||||||
ct, _, err = mime.ParseMediaType(ct)
|
|
||||||
switch {
|
|
||||||
case ct == "application/x-www-form-urlencoded":
|
|
||||||
var reader io.Reader = r.Body
|
|
||||||
maxFormSize := int64(1<<63 - 1)
|
|
||||||
if _, ok := r.Body.(*maxBytesReader); !ok {
|
|
||||||
maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
|
|
||||||
reader = io.LimitReader(r.Body, maxFormSize+1)
|
|
||||||
}
|
|
||||||
b, e := io.ReadAll(reader)
|
|
||||||
if e != nil {
|
|
||||||
if err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if int64(len(b)) > maxFormSize {
|
|
||||||
err = errors.New("http: POST too large")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
vs, e = url.ParseQuery(string(b))
|
|
||||||
if err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
case ct == "multipart/form-data":
|
|
||||||
// handled by ParseMultipartForm (which is calling us, or should be)
|
|
||||||
// TODO(bradfitz): there are too many possible
|
|
||||||
// orders to call too many functions here.
|
|
||||||
// Clean this up and write more tests.
|
|
||||||
// request_test.go contains the start of this,
|
|
||||||
// in TestParseMultipartFormOrder and others.
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type JustId struct{ Id string `json:"id" validate:"required"` }
|
|
||||||
|
|
||||||
type Generic struct{ reflect.Type }
|
|
||||||
|
|
||||||
var NotFoundError = errors.New("Not found")
|
|
||||||
var CouldNotInsert = errors.New("Could not insert")
|
|
||||||
|
|
||||||
func generateQuery(t reflect.Type) (query string, nargs int) {
|
|
||||||
nargs = t.NumField()
|
|
||||||
query = ""
|
|
||||||
|
|
||||||
for i := 0; i < nargs; i += 1 {
|
|
||||||
field := t.Field(i)
|
|
||||||
name, ok := field.Tag.Lookup("db")
|
|
||||||
if !ok {
|
|
||||||
name = field.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == "__nil__" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
query += strings.ToLower(name) + ","
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the last comma
|
|
||||||
query = query[0 : len(query)-1]
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type QueryInterface interface {
|
|
||||||
Prepare(str string) (*sql.Stmt, error)
|
|
||||||
Query(query string, args ...any) (*sql.Rows, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDbMultitple[T interface{}](c QueryInterface, tablename string, args ...any) ([]*T, error) {
|
|
||||||
t := reflect.TypeFor[T]()
|
|
||||||
|
|
||||||
query, nargs := generateQuery(t)
|
|
||||||
|
|
||||||
db_query, err := c.Prepare(fmt.Sprintf("select %s from %s", query, tablename))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db_query.Close()
|
|
||||||
|
|
||||||
rows, err := db_query.Query(args...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
list := []*T{}
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
item := new(T)
|
|
||||||
if err = mapRow(item, rows, nargs); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
list = append(list, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
return list, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func mapRow(store interface{}, rows *sql.Rows, nargs int) (err error) {
|
|
||||||
err = nil
|
|
||||||
|
|
||||||
val := reflect.Indirect(reflect.ValueOf(store))
|
|
||||||
scan_args := make([]interface{}, nargs)
|
|
||||||
for i := 0; i < nargs; i++ {
|
|
||||||
valueField := val.Field(i)
|
|
||||||
scan_args[i] = valueField.Addr().Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
err = rows.Scan(scan_args...)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func InsertReturnId(c *Context, store interface{}, tablename string, returnName string) (id string, err error) {
|
|
||||||
t := reflect.TypeOf(store).Elem()
|
|
||||||
|
|
||||||
query, nargs := generateQuery(t)
|
|
||||||
|
|
||||||
query2 := ""
|
|
||||||
for i := 0; i < nargs; i += 1 {
|
|
||||||
query2 += fmt.Sprintf("$%d,", i+1)
|
|
||||||
}
|
|
||||||
// Remove last quotation
|
|
||||||
query2 = query2[0 : len(query2)-1]
|
|
||||||
|
|
||||||
val := reflect.ValueOf(store).Elem()
|
|
||||||
scan_args := make([]interface{}, nargs)
|
|
||||||
for i := 0; i < nargs; i++ {
|
|
||||||
valueField := val.Field(i)
|
|
||||||
scan_args[i] = valueField.Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
rows, err := c.Db.Query(fmt.Sprintf("insert into %s (%s) values (%s) returning %s", tablename, query, query2, returnName), scan_args...)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
if !rows.Next() {
|
|
||||||
return "", CouldNotInsert
|
|
||||||
}
|
|
||||||
|
|
||||||
err = rows.Scan(&id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDBOnce(db QueryInterface, store interface{}, tablename string, args ...any) error {
|
|
||||||
t := reflect.TypeOf(store).Elem()
|
|
||||||
|
|
||||||
query, nargs := generateQuery(t)
|
|
||||||
|
|
||||||
rows, err := db.Query(fmt.Sprintf("select %s from %s", query, tablename), args...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
if !rows.Next() {
|
|
||||||
return NotFoundError
|
|
||||||
}
|
|
||||||
|
|
||||||
err = nil
|
|
||||||
|
|
||||||
val := reflect.ValueOf(store).Elem()
|
|
||||||
scan_args := make([]interface{}, nargs)
|
|
||||||
for i := 0; i < nargs; i++ {
|
|
||||||
valueField := val.Field(i)
|
|
||||||
scan_args[i] = valueField.Addr().Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
err = rows.Scan(scan_args...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateStatus(c *Context, table string, id string, status int) (err error) {
|
|
||||||
_, err = c.Db.Exec(fmt.Sprintf("update %s set status = $1 where id = $2", table), status, id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
8
users.go
8
users.go
@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
dbtypes "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
dbtypes "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
"git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -226,7 +226,7 @@ func usersEndpints(db *sql.DB, handle *Handle) {
|
|||||||
Id string
|
Id string
|
||||||
}
|
}
|
||||||
|
|
||||||
err := utils.GetDBOnce(c, &data, "users where id=$1", dat.Id)
|
err := GetDBOnce(c, &data, "users where id=$1", dat.Id)
|
||||||
if err == NotFoundError {
|
if err == NotFoundError {
|
||||||
return c.JsonBadRequest("User does not exist")
|
return c.JsonBadRequest("User does not exist")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -235,7 +235,7 @@ func usersEndpints(db *sql.DB, handle *Handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var data JustId
|
var data JustId
|
||||||
err := utils.GetDBOnce(c, &data, "users where email=$1", dat.Email)
|
err := GetDBOnce(c, &data, "users where email=$1", dat.Email)
|
||||||
if err != nil && err != NotFoundError {
|
if err != nil && err != NotFoundError {
|
||||||
return c.E500M("Falied to get data for user", err)
|
return c.E500M("Falied to get data for user", err)
|
||||||
}
|
}
|
||||||
@ -260,7 +260,7 @@ func usersEndpints(db *sql.DB, handle *Handle) {
|
|||||||
User_Type int
|
User_Type int
|
||||||
}
|
}
|
||||||
|
|
||||||
err = utils.GetDBOnce(c, &user, "users where id=$1", dat.Id)
|
err = GetDBOnce(c, &user, "users where id=$1", dat.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.E500M("Failed to get user data", err)
|
return c.E500M("Failed to get user data", err)
|
||||||
}
|
}
|
||||||
|
@ -1,101 +1,101 @@
|
|||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { userStore } from 'routes/UserStore.svelte';
|
import { userStore } from 'routes/UserStore.svelte';
|
||||||
|
|
||||||
const API = "/api";
|
const API = '/api';
|
||||||
|
|
||||||
export async function get(url: string) {
|
export async function get(url: string) {
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
//headers.append('content-type', 'application/json');
|
//headers.append('content-type', 'application/json');
|
||||||
headers.append('response-type', 'application/json');
|
headers.append('response-type', 'application/json');
|
||||||
if (userStore.user) {
|
if (userStore.user) {
|
||||||
headers.append('token', userStore.user.token);
|
headers.append('token', userStore.user.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
let r = await fetch(`${API}/${url}`, {
|
const r = await fetch(`${API}/${url}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: headers,
|
headers: headers
|
||||||
});
|
});
|
||||||
|
|
||||||
if (r.status === 401) {
|
if (r.status === 401) {
|
||||||
userStore.user = undefined;
|
userStore.user = undefined;
|
||||||
goto("/login")
|
goto('/login');
|
||||||
} else if (r.status !== 200) {
|
} else if (r.status !== 200) {
|
||||||
throw r;
|
throw r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.json();
|
return r.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function post(url: string, body: any) {
|
export async function post(url: string, body: any) {
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
headers.append('content-type', 'application/json');
|
headers.append('content-type', 'application/json');
|
||||||
if (userStore.user) {
|
if (userStore.user) {
|
||||||
headers.append('token', userStore.user.token);
|
headers.append('token', userStore.user.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
let r = await fetch(`${API}/${url}`, {
|
const r = await fetch(`${API}/${url}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: headers,
|
headers: headers,
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (r.status === 401) {
|
|
||||||
userStore.user = undefined;
|
|
||||||
goto("/login")
|
|
||||||
throw r;
|
|
||||||
} else if (r.status !== 200) {
|
|
||||||
throw r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.json();
|
if (r.status === 401) {
|
||||||
|
userStore.user = undefined;
|
||||||
|
goto('/login');
|
||||||
|
throw r;
|
||||||
|
} else if (r.status !== 200) {
|
||||||
|
throw r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function rdelete(url: string, body: any) {
|
export async function rdelete(url: string, body: any) {
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
headers.append('content-type', 'application/json');
|
headers.append('content-type', 'application/json');
|
||||||
if (userStore.user) {
|
if (userStore.user) {
|
||||||
headers.append('token', userStore.user.token);
|
headers.append('token', userStore.user.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
let r = await fetch(`${API}/${url}`, {
|
const r = await fetch(`${API}/${url}`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: headers,
|
headers: headers,
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (r.status === 401) {
|
if (r.status === 401) {
|
||||||
userStore.user = undefined;
|
userStore.user = undefined;
|
||||||
goto("/login")
|
goto('/login');
|
||||||
} else if (r.status !== 200) {
|
} else if (r.status !== 200) {
|
||||||
throw r;
|
throw r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.json();
|
return r.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function postFormData(url: string, body: FormData) {
|
export async function postFormData(url: string, body: FormData) {
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
//headers.append('content-type', 'multipart/form-data');
|
//headers.append('content-type', 'multipart/form-data');
|
||||||
headers.append('response-type', 'application/json');
|
headers.append('response-type', 'application/json');
|
||||||
if (userStore.user) {
|
if (userStore.user) {
|
||||||
headers.append('token', userStore.user.token);
|
headers.append('token', userStore.user.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
let r = await fetch(`${API}/${url}`, {
|
const r = await fetch(`${API}/${url}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: headers,
|
headers: headers,
|
||||||
body: body,
|
body: body
|
||||||
});
|
});
|
||||||
|
|
||||||
if (r.status == 401) {
|
if (r.status == 401) {
|
||||||
userStore.user = undefined;
|
userStore.user = undefined;
|
||||||
goto('/login');
|
goto('/login');
|
||||||
throw new Error("Redirect");
|
throw new Error('Redirect');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.status !== 200) {
|
if (r.status !== 200) {
|
||||||
throw r;
|
throw r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.json();
|
return r.json();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user