add ability to remove user and add task depndencies closes #69
This commit is contained in:
parent
00ddb91a22
commit
8ece8306dd
3
go.mod
3
go.mod
@ -21,6 +21,9 @@ require (
|
|||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.19.0 // indirect
|
github.com/go-playground/validator/v10 v10.19.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
13
go.sum
13
go.sum
@ -10,6 +10,7 @@ github.com/charmbracelet/log v0.2.5 h1:1yVvyKCKVV639RR4LIq1iy1Cs1AKxuNO+Hx2LJtk7
|
|||||||
github.com/charmbracelet/log v0.2.5/go.mod h1:nQGK8tvc4pS9cvVEH/pWJiZ50eUq1aoXUOjGpXvdD0k=
|
github.com/charmbracelet/log v0.2.5/go.mod h1:nQGK8tvc4pS9cvVEH/pWJiZ50eUq1aoXUOjGpXvdD0k=
|
||||||
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
|
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
|
||||||
github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
|
github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e h1:9+2AEFZymTi25FIIcDwuzcOPH04z9+fV6XeLiGORPDI=
|
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e h1:9+2AEFZymTi25FIIcDwuzcOPH04z9+fV6XeLiGORPDI=
|
||||||
@ -34,6 +35,12 @@ github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
|||||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
@ -53,11 +60,15 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
|||||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||||
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
|
github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
|
||||||
github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
@ -87,3 +98,5 @@ google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175
|
|||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@ -68,35 +68,25 @@ type BaseModel struct {
|
|||||||
Status int
|
Status int
|
||||||
Id string
|
Id string
|
||||||
|
|
||||||
ModelType int
|
ModelType int `db:"model_type"`
|
||||||
ImageMode int
|
ImageModeRaw string `db:"color_mode"`
|
||||||
Width int
|
ImageMode int `db:"0"`
|
||||||
Height int
|
Width int
|
||||||
Format string
|
Height int
|
||||||
|
Format string
|
||||||
|
CanTrain int `db:"can_train"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var ModelNotFoundError = errors.New("Model not found error")
|
var ModelNotFoundError = errors.New("Model not found error")
|
||||||
|
|
||||||
func GetBaseModel(db *sql.DB, id string) (base *BaseModel, err error) {
|
func GetBaseModel(db *sql.DB, id string) (base *BaseModel, err error) {
|
||||||
rows, err := db.Query("select name, status, id, width, height, color_mode, format, model_type from models where id=$1;", id)
|
var model BaseModel
|
||||||
|
err = GetDBOnce(db, &model, "models where id=$1", id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
model.ImageMode = StringToImageMode(model.ImageModeRaw)
|
||||||
|
return &model, nil
|
||||||
if !rows.Next() {
|
|
||||||
return nil, ModelNotFoundError
|
|
||||||
}
|
|
||||||
|
|
||||||
base = &BaseModel{}
|
|
||||||
var colorMode string
|
|
||||||
err = rows.Scan(&base.Name, &base.Status, &base.Id, &base.Width, &base.Height, &colorMode, &base.Format, &base.ModelType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
base.ImageMode = StringToImageMode(colorMode)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m BaseModel) CanEval() bool {
|
func (m BaseModel) CanEval() bool {
|
||||||
|
@ -7,7 +7,8 @@ import (
|
|||||||
type UserType int
|
type UserType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
User_Not_Auth UserType = iota
|
User_Deleted UserType = iota - 1
|
||||||
|
User_Not_Auth
|
||||||
User_Normal
|
User_Normal
|
||||||
User_Admin
|
User_Admin
|
||||||
)
|
)
|
||||||
|
@ -439,6 +439,8 @@ func handleDataUpload(handle *Handle) {
|
|||||||
return c.SendJSONStatus(http.StatusNotFound, "Model not found")
|
return c.SendJSONStatus(http.StatusNotFound, "Model not found")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return c.Error500(err)
|
return c.Error500(err)
|
||||||
|
} else if model.CanTrain == 0 {
|
||||||
|
return c.JsonBadRequest("Model can not be trained!")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO mk this path configurable
|
// TODO mk this path configurable
|
||||||
@ -468,6 +470,10 @@ func handleDataUpload(handle *Handle) {
|
|||||||
model, err := GetBaseModel(c.Db, obj.Id)
|
model, err := GetBaseModel(c.Db, obj.Id)
|
||||||
if err == ModelNotFoundError {
|
if err == ModelNotFoundError {
|
||||||
return c.JsonBadRequest("Model not found")
|
return c.JsonBadRequest("Model not found")
|
||||||
|
} else if err != nil {
|
||||||
|
return c.E500M("Failed to get model information", err)
|
||||||
|
} else if model.CanTrain == 0 {
|
||||||
|
return c.JsonBadRequest("Model can not be trained!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if model.ModelType != 2 && model.Status != CONFIRM_PRE_TRAINING || model.ModelType == 2 && model.Status != CONFIRM_PRE_TRAINING && model.Status != READY {
|
if model.ModelType != 2 && model.Status != CONFIRM_PRE_TRAINING || model.ModelType == 2 && model.Status != CONFIRM_PRE_TRAINING && model.Status != READY {
|
||||||
@ -516,6 +522,8 @@ func handleDataUpload(handle *Handle) {
|
|||||||
return c.JsonBadRequest("Could not find the model")
|
return c.JsonBadRequest("Could not find the model")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return c.E500M("Error getting model information", err)
|
return c.E500M("Error getting model information", err)
|
||||||
|
} else if model.CanTrain == 0 {
|
||||||
|
return c.JsonBadRequest("Model can not be trained!")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO make this work for zip files as well
|
// TODO make this work for zip files as well
|
||||||
@ -622,6 +630,8 @@ func handleDataUpload(handle *Handle) {
|
|||||||
return c.SendJSONStatus(http.StatusNotFound, "Model not found")
|
return c.SendJSONStatus(http.StatusNotFound, "Model not found")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return c.Error500(err)
|
return c.Error500(err)
|
||||||
|
} else if model.CanTrain == 0 {
|
||||||
|
return c.JsonBadRequest("Model can not be trained!")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO work in allowing the model to add new in the pre ready moment
|
// TODO work in allowing the model to add new in the pre ready moment
|
||||||
|
@ -9,20 +9,27 @@ import (
|
|||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func deleteModelJSON(c *Context, id string) *Error {
|
func DeleteModel(c BasePack, id string) (err error) {
|
||||||
c.Logger.Warnf("Removing model with id: %s", id)
|
c.GetLogger().Warnf("Removing model with id: %s", id)
|
||||||
_, err := c.Db.Exec("delete from models where id=$1;", id)
|
_, err = c.GetDb().Exec("delete from models where id=$1;", id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.E500M("Failed to delete models", err)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
model_path := path.Join("./savedData", id)
|
model_path := path.Join("./savedData", id)
|
||||||
c.Logger.Warnf("Removing folder of model with id: %s at %s", id, model_path)
|
c.GetLogger().Warnf("Removing folder of model with id: %s at %s", id, model_path)
|
||||||
err = os.RemoveAll(model_path)
|
err = os.RemoveAll(model_path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.E500M("Failed to remove data", err)
|
return
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteModelJSON(c *Context, id string) *Error {
|
||||||
|
err := DeleteModel(c, id)
|
||||||
|
if err != nil {
|
||||||
|
return c.E500M("Failed to delete models", err)
|
||||||
|
}
|
||||||
return c.SendJSON(id)
|
return c.SendJSON(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,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 {
|
||||||
task.UpdateStatusLog(base, TASK_FAILED_RUNNING, "Failed to obtain the model")
|
task.UpdateStatusLog(base, TASK_FAILED_RUNNING, "Failed to obtain the model")
|
||||||
return err
|
return err
|
||||||
|
@ -1625,7 +1625,7 @@ func trainExpandable(c *Context, model *BaseModel) {
|
|||||||
func RunTaskTrain(b BasePack, task Task) (err error) {
|
func RunTaskTrain(b BasePack, task Task) (err error) {
|
||||||
l := b.GetLogger()
|
l := b.GetLogger()
|
||||||
|
|
||||||
model, err := GetBaseModel(b.GetDb(), task.ModelId)
|
model, err := GetBaseModel(b.GetDb(), *task.ModelId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
task.UpdateStatusLog(b, TASK_FAILED_RUNNING, "Failed to get model information")
|
task.UpdateStatusLog(b, TASK_FAILED_RUNNING, "Failed to get model information")
|
||||||
l.Error("Failed to get model information", "err", err)
|
l.Error("Failed to get model information", "err", err)
|
||||||
@ -1683,7 +1683,7 @@ func RunTaskTrain(b BasePack, task Task) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RunTaskRetrain(b BasePack, task Task) (err error) {
|
func RunTaskRetrain(b BasePack, task Task) (err error) {
|
||||||
model, err := GetBaseModel(b.GetDb(), task.ModelId)
|
model, err := GetBaseModel(b.GetDb(), *task.ModelId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if model.Status != READY_RETRAIN {
|
} else if model.Status != READY_RETRAIN {
|
||||||
@ -1759,6 +1759,8 @@ func handleTrain(handle *Handle) {
|
|||||||
return c.JsonBadRequest("Model not found")
|
return c.JsonBadRequest("Model not found")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return c.E500M("Failed to get model information", err)
|
return c.E500M("Failed to get model information", err)
|
||||||
|
} else if model.CanTrain == 0 {
|
||||||
|
return c.JsonBadRequest("Model can not be trained!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if model.Status != CONFIRM_PRE_TRAINING {
|
if model.Status != CONFIRM_PRE_TRAINING {
|
||||||
@ -1813,6 +1815,8 @@ func handleTrain(handle *Handle) {
|
|||||||
return c.E500M("Faield to get model", err)
|
return c.E500M("Faield to get model", err)
|
||||||
} else if model.Status != READY && model.Status != READY_RETRAIN_FAILED && model.Status != READY_ALTERATION_FAILED {
|
} else if model.Status != READY && model.Status != READY_RETRAIN_FAILED && model.Status != READY_ALTERATION_FAILED {
|
||||||
return c.JsonBadRequest("Model in invalid status for re-training")
|
return c.JsonBadRequest("Model in invalid status for re-training")
|
||||||
|
} else if model.CanTrain == 0 {
|
||||||
|
return c.JsonBadRequest("Model can not be trained!")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Logger.Info("Expanding definitions for models", "id", model.Id)
|
c.Logger.Info("Expanding definitions for models", "id", model.Id)
|
||||||
|
@ -55,6 +55,8 @@ func handleUpload(handler *Handle) {
|
|||||||
model, err := GetBaseModel(c.Db, requestData.ModelId)
|
model, err := GetBaseModel(c.Db, requestData.ModelId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Error500(err)
|
return c.Error500(err)
|
||||||
|
} else if model.CanTrain == 0 {
|
||||||
|
return c.JsonBadRequest("Model can not be trained!")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch model.Status {
|
switch model.Status {
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/train"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/train"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/users"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -71,6 +72,14 @@ func runner(config Config, db *sql.DB, task_channel chan Task, index int, back_c
|
|||||||
logger.Error("Failed to tain the model", "error", err)
|
logger.Error("Failed to tain the model", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
back_channel <- index
|
||||||
|
continue
|
||||||
|
} else if task.TaskType == int(TASK_TYPE_DELETE_USER) {
|
||||||
|
logger.Warn("User deleting Task")
|
||||||
|
if err = DeleteUser(base, task); err != nil {
|
||||||
|
logger.Error("Failed to tain the model", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
back_channel <- index
|
back_channel <- index
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -168,16 +177,23 @@ func RunnerOrchestrator(db *sql.DB, config Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if task_to_dispatch == nil {
|
if task_to_dispatch == nil {
|
||||||
var task Task
|
var task TaskT
|
||||||
err := GetDBOnce(db, &task, "tasks where status=$1 limit 1", TASK_TODO)
|
err := GetDBOnce(db, &task, "tasks as t "+
|
||||||
|
// Get depenencies
|
||||||
|
"left join tasks_dependencies as td on t.id=td.main_id "+
|
||||||
|
// Get the task that the depencey resolves to
|
||||||
|
"left join tasks as t2 on t2.id=td.dependent_id "+
|
||||||
|
"where t.status=1 "+
|
||||||
|
"group by t.id having count(td.id) filter (where t2.status in (0,1,2,3)) = 0;")
|
||||||
if err != NotFoundError && err != nil {
|
if err != NotFoundError && err != nil {
|
||||||
log.Error("Failed to get tasks from db")
|
log.Error("Failed to get tasks from db", "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err == NotFoundError {
|
if err == NotFoundError {
|
||||||
task_to_dispatch = nil
|
task_to_dispatch = nil
|
||||||
} else {
|
} else {
|
||||||
task_to_dispatch = &task
|
temp := Task(task)
|
||||||
|
task_to_dispatch = &temp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
type Task struct {
|
type Task struct {
|
||||||
Id string `db:"id" json:"id"`
|
Id string `db:"id" json:"id"`
|
||||||
UserId string `db:"user_id" json:"user_id"`
|
UserId string `db:"user_id" json:"user_id"`
|
||||||
ModelId string `db:"model_id" json:"model_id"`
|
ModelId *string `db:"model_id" json:"model_id"`
|
||||||
Status int `db:"status" json:"status"`
|
Status int `db:"status" json:"status"`
|
||||||
StatusMessage string `db:"status_message" json:"status_message"`
|
StatusMessage string `db:"status_message" json:"status_message"`
|
||||||
UserConfirmed int `db:"user_confirmed" json:"user_confirmed"`
|
UserConfirmed int `db:"user_confirmed" json:"user_confirmed"`
|
||||||
@ -21,6 +21,27 @@ type Task struct {
|
|||||||
CreatedOn time.Time `db:"created_on" json:"created"`
|
CreatedOn time.Time `db:"created_on" json:"created"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find better way todo this
|
||||||
|
type TaskT struct {
|
||||||
|
Id string `db:"t.id" json:"id"`
|
||||||
|
UserId string `db:"t.user_id" json:"user_id"`
|
||||||
|
ModelId *string `db:"t.model_id" json:"model_id"`
|
||||||
|
Status int `db:"t.status" json:"status"`
|
||||||
|
StatusMessage string `db:"t.status_message" json:"status_message"`
|
||||||
|
UserConfirmed int `db:"t.user_confirmed" json:"user_confirmed"`
|
||||||
|
Compacted int `db:"t.compacted" json:"compacted"`
|
||||||
|
TaskType int `db:"t.task_type" json:"type"`
|
||||||
|
ExtraTaskInfo string `db:"t.extra_task_info" json:"extra_task_info"`
|
||||||
|
Result string `db:"t.result" json:"result"`
|
||||||
|
CreatedOn time.Time `db:"t.created_on" json:"created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TaskDependents struct {
|
||||||
|
Id string `db:"id" json:"id"`
|
||||||
|
MainId string `db:"main_id" json:"main_id"`
|
||||||
|
DependentId string `db:"dependent_id" json:"dependent_id"`
|
||||||
|
}
|
||||||
|
|
||||||
type TaskStatus int
|
type TaskStatus int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -39,6 +60,7 @@ const (
|
|||||||
TASK_TYPE_CLASSIFICATION TaskType = 1 + iota
|
TASK_TYPE_CLASSIFICATION TaskType = 1 + iota
|
||||||
TASK_TYPE_TRAINING
|
TASK_TYPE_TRAINING
|
||||||
TASK_TYPE_RETRAINING
|
TASK_TYPE_RETRAINING
|
||||||
|
TASK_TYPE_DELETE_USER
|
||||||
)
|
)
|
||||||
|
|
||||||
type TaskAgreement int
|
type TaskAgreement int
|
||||||
@ -82,3 +104,15 @@ func (t Task) SetResult(base BasePack, result any) (err error) {
|
|||||||
_, err = base.GetDb().Exec("update tasks set result=$1 where id=$2", text, t.Id)
|
_, err = base.GetDb().Exec("update tasks set result=$1 where id=$2", text, t.Id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t Task) Depend(base BasePack, depend_id string) (err error) {
|
||||||
|
var dependency = struct {
|
||||||
|
Main string `db:"main_id"`
|
||||||
|
Dependent string `db:"dependent_id"`
|
||||||
|
}{
|
||||||
|
Main: t.Id,
|
||||||
|
Dependent: depend_id,
|
||||||
|
}
|
||||||
|
_, err = InsertReturnId(base.GetDb(), &dependency, "tasks_dependencies", "id")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package users
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@ -12,6 +12,8 @@ import (
|
|||||||
|
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
. "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"
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -80,7 +82,31 @@ func generateToken(db *sql.DB, email string, password string, name string) (stri
|
|||||||
return token, true
|
return token, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func usersEndpints(db *sql.DB, handle *Handle) {
|
func DeleteUser(base BasePack, task Task) (err error) {
|
||||||
|
ids, err := GetDbMultitple[JustId](base.GetDb(), "models where user_id=$1;", task.ExtraTaskInfo)
|
||||||
|
if err != nil {
|
||||||
|
task.UpdateStatusLog(base, TASK_FAILED_RUNNING, "Could not get models list")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range ids {
|
||||||
|
err = DeleteModel(base, ids[i].Id)
|
||||||
|
if err != nil {
|
||||||
|
base.GetLogger().Error("Could not delete model", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = base.GetDb().Exec("delete from users where id=$1", task.ExtraTaskInfo)
|
||||||
|
if err != nil {
|
||||||
|
task.UpdateStatusLog(base, TASK_FAILED_RUNNING, "Could not delete user")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
task.UpdateStatusLog(base, TASK_DONE, "User deleted with success")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func UsersEndpints(db *sql.DB, handle *Handle) {
|
||||||
|
|
||||||
type UserLogin struct {
|
type UserLogin struct {
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
@ -98,6 +124,10 @@ func usersEndpints(db *sql.DB, handle *Handle) {
|
|||||||
return c.E500M("Failed to get user from token", err)
|
return c.E500M("Failed to get user from token", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.UserType == int(User_Deleted) {
|
||||||
|
return c.JsonBadRequest("Your user is in the process of being deleted!")
|
||||||
|
}
|
||||||
|
|
||||||
type UserReturn struct {
|
type UserReturn struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
@ -381,4 +411,82 @@ func usersEndpints(db *sql.DB, handle *Handle) {
|
|||||||
|
|
||||||
return c.SendJSON("Ok")
|
return c.SendJSON("Ok")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
type DeleteUser struct {
|
||||||
|
Id string `json:"id" validate:"required"`
|
||||||
|
Password string `json:"password" validate:"required"`
|
||||||
|
}
|
||||||
|
DeleteAuthJson(handle, "/user/delete", User_Normal, func(c *Context, obj *DeleteUser) *Error {
|
||||||
|
// TODO let admin delete users
|
||||||
|
if c.User.Id != obj.Id {
|
||||||
|
return c.E500M("TODO implement this for admins", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO let admin delete users
|
||||||
|
// Verify the user password
|
||||||
|
_, generated := generateToken(c.Db, c.User.Email, obj.Password, "User Verification")
|
||||||
|
if !generated {
|
||||||
|
return c.JsonBadRequest("Password provided is incorrect")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable the ability for the user to create new tasks
|
||||||
|
_, err := c.Db.Exec(
|
||||||
|
"update models as m set can_train=0 "+
|
||||||
|
"from users as u "+
|
||||||
|
"where u.id=$1 and u.id=m.user_id;",
|
||||||
|
obj.Id,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return c.E500M("Failed to stop the models", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateNewTask struct {
|
||||||
|
UserId string `db:"user_id"`
|
||||||
|
TaskType int `db:"task_type"`
|
||||||
|
Status int `db:"status"`
|
||||||
|
ExtraTaskInfo string `db:"extra_task_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
newTask := CreateNewTask{
|
||||||
|
UserId: c.Handle.Config.ServiceUser.UserId,
|
||||||
|
// TODO move this to an enum
|
||||||
|
TaskType: int(TASK_TYPE_DELETE_USER),
|
||||||
|
Status: TASK_PREPARING,
|
||||||
|
ExtraTaskInfo: obj.Id,
|
||||||
|
}
|
||||||
|
t_id, err := InsertReturnId(c, &newTask, "tasks", "id")
|
||||||
|
if err != nil {
|
||||||
|
return c.E500M("Failed to create task", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
task := Task{Id: t_id}
|
||||||
|
|
||||||
|
type taskId struct {
|
||||||
|
Id string `db:"t.id"`
|
||||||
|
}
|
||||||
|
tasks, err := GetDbMultitple[taskId](c, "tasks as t "+
|
||||||
|
"left join models as m on m.id=t.model_id "+
|
||||||
|
"where (t.user_id=$1 or m.user_id=$1) and t.status in (0,1,2,3) "+
|
||||||
|
"group by t.id;",
|
||||||
|
obj.Id)
|
||||||
|
|
||||||
|
for i := range tasks {
|
||||||
|
err = task.Depend(c, tasks[i].Id)
|
||||||
|
if err != nil {
|
||||||
|
c.Logger.Error("Failed to mark task as depency", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = task.UpdateStatus(c, TASK_TODO, "Task ready")
|
||||||
|
if err != nil {
|
||||||
|
return c.E500M("Failed to mark task as ready", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.Db.Exec("update users set user_type=-1 where id=$1", obj.Id)
|
||||||
|
if err != nil {
|
||||||
|
return c.E500M("Failed to delete user", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendJSON("User to be deleted")
|
||||||
|
})
|
||||||
}
|
}
|
@ -97,7 +97,7 @@ func (c *Config) Cleanup(db *sql.DB) {
|
|||||||
failLog(err)
|
failLog(err)
|
||||||
_, err = db.Exec("update models set status=$1 where status=$2", FAILED_PREPARING, PREPARING)
|
_, err = db.Exec("update models set status=$1 where status=$2", FAILED_PREPARING, PREPARING)
|
||||||
failLog(err)
|
failLog(err)
|
||||||
_, err = db.Exec("update tasks set status=$1 where status=$2", TASK_PICKED_UP, TASK_TODO)
|
_, err = db.Exec("update tasks set status=$1 where status=$2", TASK_TODO, TASK_PICKED_UP)
|
||||||
failLog(err)
|
failLog(err)
|
||||||
|
|
||||||
tasks, err := GetDbMultitple[Task](db, "tasks where status=$1", TASK_RUNNING)
|
tasks, err := GetDbMultitple[Task](db, "tasks where status=$1", TASK_RUNNING)
|
||||||
|
3
main.go
3
main.go
@ -10,6 +10,7 @@ import (
|
|||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/runner"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/runner"
|
||||||
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/users"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ func main() {
|
|||||||
// TODO Handle this in other way
|
// TODO Handle this in other way
|
||||||
handle.ReadTypesFilesApi("/savedData/", ".", []string{".png", ".jpeg"}, []string{"image/png", "image/jpeg"})
|
handle.ReadTypesFilesApi("/savedData/", ".", []string{".png", ".jpeg"}, []string{"image/png", "image/jpeg"})
|
||||||
|
|
||||||
usersEndpints(db, handle)
|
UsersEndpints(db, handle)
|
||||||
HandleModels(handle)
|
HandleModels(handle)
|
||||||
HandleTasks(handle)
|
HandleTasks(handle)
|
||||||
|
|
||||||
|
@ -10,13 +10,14 @@ create table if not exists models (
|
|||||||
-- -1: failed preparing
|
-- -1: failed preparing
|
||||||
-- 1: preparing
|
-- 1: preparing
|
||||||
status integer default 1,
|
status integer default 1,
|
||||||
|
|
||||||
-- Types:
|
-- Types:
|
||||||
-- 0: Unset
|
-- 0: Unset
|
||||||
-- 1: simple
|
-- 1: simple
|
||||||
-- 2: expandable
|
-- 2: expandable
|
||||||
model_type integer default 0,
|
model_type integer default 0,
|
||||||
|
|
||||||
|
can_train integer default 1,
|
||||||
width integer,
|
width integer,
|
||||||
height integer,
|
height integer,
|
||||||
color_mode varchar (20),
|
color_mode varchar (20),
|
||||||
@ -51,7 +52,7 @@ create table if not exists model_data_point (
|
|||||||
status_message text
|
status_message text
|
||||||
);
|
);
|
||||||
|
|
||||||
-- drop table if exists model_definition;
|
-- drop table if exists model_definition;
|
||||||
create table if not exists model_definition (
|
create table if not exists model_definition (
|
||||||
id uuid primary key default gen_random_uuid(),
|
id uuid primary key default gen_random_uuid(),
|
||||||
model_id uuid references models (id) on delete cascade,
|
model_id uuid references models (id) on delete cascade,
|
||||||
@ -82,10 +83,10 @@ create table if not exists model_definition_layer (
|
|||||||
-- ei 28,28,1
|
-- ei 28,28,1
|
||||||
-- a 28x28 grayscale image
|
-- a 28x28 grayscale image
|
||||||
shape text not null,
|
shape text not null,
|
||||||
|
|
||||||
-- Type based on the expandability
|
-- Type based on the expandability
|
||||||
-- 0: not expandalbe model
|
-- 0: not expandalbe model
|
||||||
-- 1: fixed
|
-- 1: fixed
|
||||||
-- 2: head
|
-- 2: head
|
||||||
exp_type integer default 0
|
exp_type integer default 0
|
||||||
);
|
);
|
||||||
@ -111,4 +112,3 @@ create table if not exists exp_model_head (
|
|||||||
created_on timestamp default current_timestamp,
|
created_on timestamp default current_timestamp,
|
||||||
epoch_progress integer default 0
|
epoch_progress integer default 0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -16,19 +16,25 @@ create table if not exists tasks (
|
|||||||
|
|
||||||
result text default '',
|
result text default '',
|
||||||
extra_task_info text default '',
|
extra_task_info text default '',
|
||||||
|
|
||||||
-- -1: user said task is wrong
|
-- -1: user said task is wrong
|
||||||
-- 0: no user input
|
-- 0: no user input
|
||||||
-- 1: user said task is ok
|
-- 1: user said task is ok
|
||||||
user_confirmed integer default 0,
|
user_confirmed integer default 0,
|
||||||
|
|
||||||
-- Tells the user if the file has been already compacted into
|
-- Tells the user if the file has been already compacted into
|
||||||
-- embendings
|
-- embendings
|
||||||
compacted integer default 0,
|
compacted integer default 0,
|
||||||
|
|
||||||
-- TODO move the training tasks to here
|
-- TODO move the training tasks to here
|
||||||
-- 1: Classification
|
-- 1: Classification
|
||||||
task_type integer,
|
task_type integer,
|
||||||
|
|
||||||
created_on timestamp default current_timestamp
|
created_on timestamp default current_timestamp
|
||||||
)
|
);
|
||||||
|
|
||||||
|
create table if not exists tasks_dependencies (
|
||||||
|
id uuid primary key default gen_random_uuid(),
|
||||||
|
main_id uuid references tasks (id) on delete cascade not null,
|
||||||
|
dependent_id uuid references tasks (id) on delete cascade not null
|
||||||
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import Notifications from './lib/Notifications.svelte';
|
||||||
import { userStore } from './routes/UserStore.svelte';
|
import { userStore } from './routes/UserStore.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -26,6 +27,8 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<Notifications />
|
||||||
|
|
||||||
<style class="scss">
|
<style class="scss">
|
||||||
nav {
|
nav {
|
||||||
background: #ececec;
|
background: #ececec;
|
||||||
|
42
webpage/src/lib/Notifications.svelte
Normal file
42
webpage/src/lib/Notifications.svelte
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { fly, fade } from 'svelte/transition';
|
||||||
|
import { notificationStore } from './NotificationsStore.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="notifications">
|
||||||
|
{#each notificationStore.notifications as noti}
|
||||||
|
<div
|
||||||
|
class="notification"
|
||||||
|
class:noti-success={noti.type === 'success'}
|
||||||
|
class:noti-danger={noti.type === 'danger'}
|
||||||
|
class:noti-info={noti.type === 'info'}
|
||||||
|
in:fly|global={{ duration: 300, y: -120, opacity: 0 }}
|
||||||
|
out:fly|global={{ duration: 300, y: -120, opacity: 1 }}
|
||||||
|
>
|
||||||
|
{noti.message}
|
||||||
|
{@html noti.html ?? ''}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.notifications {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: max(300px, 30%);
|
||||||
|
|
||||||
|
.notification {
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: 20px;
|
||||||
|
background: #ffffff;
|
||||||
|
margin: 15px 0;
|
||||||
|
border-radius: 20px;
|
||||||
|
|
||||||
|
&.noti-danger {
|
||||||
|
background: var(--danger-ligther);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
68
webpage/src/lib/NotificationsStore.svelte.ts
Normal file
68
webpage/src/lib/NotificationsStore.svelte.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
type NotificationType = 'danger' | 'success' | 'info';
|
||||||
|
type Notification = {
|
||||||
|
type?: NotificationType;
|
||||||
|
timeToLive?: number;
|
||||||
|
message: string;
|
||||||
|
html?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createNotificationStore(defaultTimetoLive: number) {
|
||||||
|
type InternalNotifications = {
|
||||||
|
notification: Notification;
|
||||||
|
endDate: Date;
|
||||||
|
};
|
||||||
|
let notifications = $state<InternalNotifications[]>([]);
|
||||||
|
let timeout = $state<number | undefined>();
|
||||||
|
|
||||||
|
function clearNotifications() {
|
||||||
|
const now = new Date().getTime();
|
||||||
|
let min: number | undefined = undefined;
|
||||||
|
notifications = notifications.filter((a) => {
|
||||||
|
const t = a.endDate.getTime();
|
||||||
|
if (t <= now) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (min == undefined) {
|
||||||
|
min = t;
|
||||||
|
} else if (min > t) {
|
||||||
|
min = t;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (min != undefined) {
|
||||||
|
timeout = setTimeout(clearNotifications, now - min);
|
||||||
|
} else {
|
||||||
|
timeout = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(noti: Notification) {
|
||||||
|
if (!timeout) {
|
||||||
|
timeout = setTimeout(clearNotifications, noti.timeToLive ?? defaultTimetoLive);
|
||||||
|
}
|
||||||
|
const now = new Date();
|
||||||
|
notifications.push({
|
||||||
|
notification: noti,
|
||||||
|
endDate: new Date(now.getTime() + (noti.timeToLive ?? defaultTimetoLive))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
get notifications() {
|
||||||
|
return notifications.map((a) => a.notification);
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
notifications.forEach((a) => clearInterval(a.timeout));
|
||||||
|
notifications = [];
|
||||||
|
},
|
||||||
|
add,
|
||||||
|
notify(message: string, type: NotificationType = 'danger') {
|
||||||
|
add({ message, type });
|
||||||
|
},
|
||||||
|
display(message: string) {
|
||||||
|
add({ message, type: 'danger' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const notificationStore = createNotificationStore(5000);
|
@ -108,7 +108,11 @@ export async function showMessage(
|
|||||||
if (e == null) {
|
if (e == null) {
|
||||||
return false;
|
return false;
|
||||||
} else if (e instanceof Response) {
|
} else if (e instanceof Response) {
|
||||||
messages.display(await e.json());
|
try {
|
||||||
|
messages.display(await e.json());
|
||||||
|
} catch (ex) {
|
||||||
|
showMessage(ex, messages, message);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
|
|
||||||
import BaseModelInfo from './BaseModelInfo.svelte';
|
import BaseModelInfo from './BaseModelInfo.svelte';
|
||||||
import DeleteModel from './DeleteModel.svelte';
|
import DeleteModel from './DeleteModel.svelte';
|
||||||
@ -50,16 +50,22 @@
|
|||||||
|
|
||||||
let id: string | undefined = $state();
|
let id: string | undefined = $state();
|
||||||
|
|
||||||
|
let re_query_timeout: number | undefined = undefined;
|
||||||
|
|
||||||
async function getModel() {
|
async function getModel() {
|
||||||
|
if (re_query_timeout) {
|
||||||
|
clearTimeout(re_query_timeout);
|
||||||
|
re_query_timeout = undefined;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
let temp_model: Model = await get(`models/edit?id=${id}`);
|
let temp_model: Model = await get(`models/edit?id=${id}`);
|
||||||
|
|
||||||
if ([3, 7, 6].includes(temp_model.status)) {
|
if ([3, 7, 6].includes(temp_model.status)) {
|
||||||
setTimeout(getModel, 2000);
|
re_query_timeout = setTimeout(getModel, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temp_model.status == 4) {
|
if (temp_model.status == 4) {
|
||||||
setTimeout(getModel, 5000);
|
re_query_timeout = setTimeout(getModel, 5000);
|
||||||
|
|
||||||
definitions = await get(`models/edit/definitions?id=${id}`);
|
definitions = await get(`models/edit/definitions?id=${id}`);
|
||||||
}
|
}
|
||||||
@ -108,6 +114,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if (re_query_timeout) {
|
||||||
|
clearTimeout(re_query_timeout);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Auto reload after 2s when model.status 3,4
|
// Auto reload after 2s when model.status 3,4
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
8
webpage/src/routes/user-deleted/+page.svelte
Normal file
8
webpage/src/routes/user-deleted/+page.svelte
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<h1>Your User has been deleted</h1>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -7,6 +7,7 @@
|
|||||||
import { post } from 'src/lib/requests.svelte';
|
import { post } from 'src/lib/requests.svelte';
|
||||||
import MessageSimple, { type DisplayFn } from 'src/lib/MessageSimple.svelte';
|
import MessageSimple, { type DisplayFn } from 'src/lib/MessageSimple.svelte';
|
||||||
import TokenTable from './TokenTable.svelte';
|
import TokenTable from './TokenTable.svelte';
|
||||||
|
import DeleteUser from './DeleteUser.svelte';
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (!userStore.isLogin()) {
|
if (!userStore.isLogin()) {
|
||||||
@ -110,8 +111,8 @@
|
|||||||
<button> Update </button>
|
<button> Update </button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<!-- TODO Delete -->
|
|
||||||
<TokenTable />
|
<TokenTable />
|
||||||
|
<DeleteUser />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
34
webpage/src/routes/user/info/DeleteUser.svelte
Normal file
34
webpage/src/routes/user/info/DeleteUser.svelte
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import { notificationStore } from 'src/lib/NotificationsStore.svelte';
|
||||||
|
import { rdelete, showMessage } from 'src/lib/requests.svelte';
|
||||||
|
import { userStore } from 'src/routes/UserStore.svelte';
|
||||||
|
|
||||||
|
let data = $state({ password: '' });
|
||||||
|
|
||||||
|
async function deleteUser() {
|
||||||
|
if (!userStore.user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await rdelete('user/delete', {
|
||||||
|
id: userStore.user?.id,
|
||||||
|
password: data.password
|
||||||
|
});
|
||||||
|
userStore.user = undefined;
|
||||||
|
goto('/user-deleted');
|
||||||
|
} catch (e) {
|
||||||
|
showMessage(e, notificationStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<form class="danger-bg" on:submit|preventDefault={deleteUser}>
|
||||||
|
<h2 class="no-top-margin">Delete user</h2>
|
||||||
|
Deleting the user will delete all your data stored in the service including the images.
|
||||||
|
<fieldset>
|
||||||
|
To confirm please type your password
|
||||||
|
<input name="password" type="password" required bind:value={data.password} />
|
||||||
|
</fieldset>
|
||||||
|
<button> Delete </button>
|
||||||
|
</form>
|
@ -13,6 +13,7 @@
|
|||||||
--warning: #fca311;
|
--warning: #fca311;
|
||||||
--warning-transparent: #fca31144;
|
--warning-transparent: #fca31144;
|
||||||
|
|
||||||
|
--danger-ligther: #ffe0de;
|
||||||
--danger: #ff8282;
|
--danger: #ff8282;
|
||||||
--danger-transparent: #ff828244;
|
--danger-transparent: #ff828244;
|
||||||
|
|
||||||
@ -171,3 +172,20 @@ a.button {
|
|||||||
background-color: var(--danger-transparent);
|
background-color: var(--danger-transparent);
|
||||||
border: 1px solid var(--danger);
|
border: 1px solid var(--danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
padding: 30px;
|
||||||
|
margin: 20px 0;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 2px 5px 8px 2px #66666655;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-top-margin {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box.danger-bg,
|
||||||
|
form.danger-bg {
|
||||||
|
background-color: var(--danger-transparent);
|
||||||
|
border: 1px solid var(--danger);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user