BIG MASSIVE REFACTOR OMG
Ripped out literally everything to simplify the backend as much as possible. Some of the code was so horrifically complicated it's insaneeee
This commit is contained in:
@ -9,11 +9,15 @@ package model
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Image struct {
|
||||
ID uuid.UUID `sql:"primary_key"`
|
||||
UserID *uuid.UUID
|
||||
ImageName string
|
||||
Description string
|
||||
Status Progress
|
||||
Image []byte
|
||||
CreatedAt *time.Time
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ImageLists struct {
|
||||
type ImageStacks struct {
|
||||
ID uuid.UUID `sql:"primary_key"`
|
||||
ImageID uuid.UUID
|
||||
ListID uuid.UUID
|
||||
StackID uuid.UUID
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Logs struct {
|
||||
Log string
|
||||
ImageID uuid.UUID
|
||||
CreatedAt *time.Time
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProcessingLists struct {
|
||||
ID uuid.UUID `sql:"primary_key"`
|
||||
UserID uuid.UUID
|
||||
Title string
|
||||
Fields string
|
||||
Status Progress
|
||||
CreatedAt *time.Time
|
||||
}
|
@ -16,5 +16,5 @@ type SchemaItems struct {
|
||||
Item string
|
||||
Value string
|
||||
Description string
|
||||
SchemaID uuid.UUID
|
||||
StackID uuid.UUID
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Schemas struct {
|
||||
ID uuid.UUID `sql:"primary_key"`
|
||||
ListID uuid.UUID
|
||||
}
|
@ -12,9 +12,10 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Lists struct {
|
||||
type Stacks struct {
|
||||
ID uuid.UUID `sql:"primary_key"`
|
||||
UserID uuid.UUID
|
||||
Status Progress
|
||||
Name string
|
||||
Description string
|
||||
CreatedAt *time.Time
|
@ -1,20 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserImages struct {
|
||||
ID uuid.UUID `sql:"primary_key"`
|
||||
ImageID uuid.UUID
|
||||
UserID uuid.UUID
|
||||
CreatedAt *time.Time
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type UserImagesToProcess struct {
|
||||
ID uuid.UUID `sql:"primary_key"`
|
||||
Status Progress
|
||||
ImageID uuid.UUID
|
||||
UserID uuid.UUID
|
||||
}
|
@ -9,9 +9,11 @@ package model
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Users struct {
|
||||
ID uuid.UUID `sql:"primary_key"`
|
||||
Email string
|
||||
ID uuid.UUID `sql:"primary_key"`
|
||||
Email string
|
||||
CreatedAt *time.Time
|
||||
}
|
||||
|
@ -18,13 +18,15 @@ type imageTable struct {
|
||||
|
||||
// Columns
|
||||
ID postgres.ColumnString
|
||||
UserID postgres.ColumnString
|
||||
ImageName postgres.ColumnString
|
||||
Description postgres.ColumnString
|
||||
Image postgres.ColumnBytea
|
||||
Status postgres.ColumnString
|
||||
Image postgres.ColumnString
|
||||
CreatedAt postgres.ColumnTimestampz
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type ImageTable struct {
|
||||
@ -63,12 +65,14 @@ func newImageTable(schemaName, tableName, alias string) *ImageTable {
|
||||
func newImageTableImpl(schemaName, tableName, alias string) imageTable {
|
||||
var (
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
UserIDColumn = postgres.StringColumn("user_id")
|
||||
ImageNameColumn = postgres.StringColumn("image_name")
|
||||
DescriptionColumn = postgres.StringColumn("description")
|
||||
ImageColumn = postgres.ByteaColumn("image")
|
||||
allColumns = postgres.ColumnList{IDColumn, ImageNameColumn, DescriptionColumn, ImageColumn}
|
||||
mutableColumns = postgres.ColumnList{ImageNameColumn, DescriptionColumn, ImageColumn}
|
||||
defaultColumns = postgres.ColumnList{IDColumn}
|
||||
StatusColumn = postgres.StringColumn("status")
|
||||
ImageColumn = postgres.StringColumn("image")
|
||||
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||
allColumns = postgres.ColumnList{IDColumn, UserIDColumn, ImageNameColumn, DescriptionColumn, StatusColumn, ImageColumn, CreatedAtColumn}
|
||||
mutableColumns = postgres.ColumnList{UserIDColumn, ImageNameColumn, DescriptionColumn, StatusColumn, ImageColumn, CreatedAtColumn}
|
||||
)
|
||||
|
||||
return imageTable{
|
||||
@ -76,12 +80,14 @@ func newImageTableImpl(schemaName, tableName, alias string) imageTable {
|
||||
|
||||
//Columns
|
||||
ID: IDColumn,
|
||||
UserID: UserIDColumn,
|
||||
ImageName: ImageNameColumn,
|
||||
Description: DescriptionColumn,
|
||||
Status: StatusColumn,
|
||||
Image: ImageColumn,
|
||||
CreatedAt: CreatedAtColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
||||
|
@ -1,84 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/postgres"
|
||||
)
|
||||
|
||||
var ImageLists = newImageListsTable("haystack", "image_lists", "")
|
||||
|
||||
type imageListsTable struct {
|
||||
postgres.Table
|
||||
|
||||
// Columns
|
||||
ID postgres.ColumnString
|
||||
ImageID postgres.ColumnString
|
||||
ListID postgres.ColumnString
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type ImageListsTable struct {
|
||||
imageListsTable
|
||||
|
||||
EXCLUDED imageListsTable
|
||||
}
|
||||
|
||||
// AS creates new ImageListsTable with assigned alias
|
||||
func (a ImageListsTable) AS(alias string) *ImageListsTable {
|
||||
return newImageListsTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new ImageListsTable with assigned schema name
|
||||
func (a ImageListsTable) FromSchema(schemaName string) *ImageListsTable {
|
||||
return newImageListsTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
// WithPrefix creates new ImageListsTable with assigned table prefix
|
||||
func (a ImageListsTable) WithPrefix(prefix string) *ImageListsTable {
|
||||
return newImageListsTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||
}
|
||||
|
||||
// WithSuffix creates new ImageListsTable with assigned table suffix
|
||||
func (a ImageListsTable) WithSuffix(suffix string) *ImageListsTable {
|
||||
return newImageListsTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||
}
|
||||
|
||||
func newImageListsTable(schemaName, tableName, alias string) *ImageListsTable {
|
||||
return &ImageListsTable{
|
||||
imageListsTable: newImageListsTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newImageListsTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newImageListsTableImpl(schemaName, tableName, alias string) imageListsTable {
|
||||
var (
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
ImageIDColumn = postgres.StringColumn("image_id")
|
||||
ListIDColumn = postgres.StringColumn("list_id")
|
||||
allColumns = postgres.ColumnList{IDColumn, ImageIDColumn, ListIDColumn}
|
||||
mutableColumns = postgres.ColumnList{ImageIDColumn, ListIDColumn}
|
||||
defaultColumns = postgres.ColumnList{IDColumn}
|
||||
)
|
||||
|
||||
return imageListsTable{
|
||||
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
ID: IDColumn,
|
||||
ImageID: ImageIDColumn,
|
||||
ListID: ListIDColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
@ -24,7 +24,6 @@ type imageSchemaItemsTable struct {
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type ImageSchemaItemsTable struct {
|
||||
@ -68,7 +67,6 @@ func newImageSchemaItemsTableImpl(schemaName, tableName, alias string) imageSche
|
||||
ImageIDColumn = postgres.StringColumn("image_id")
|
||||
allColumns = postgres.ColumnList{IDColumn, ValueColumn, SchemaItemIDColumn, ImageIDColumn}
|
||||
mutableColumns = postgres.ColumnList{ValueColumn, SchemaItemIDColumn, ImageIDColumn}
|
||||
defaultColumns = postgres.ColumnList{IDColumn}
|
||||
)
|
||||
|
||||
return imageSchemaItemsTable{
|
||||
@ -82,6 +80,5 @@ func newImageSchemaItemsTableImpl(schemaName, tableName, alias string) imageSche
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
||||
|
81
backend/.gen/haystack/haystack/table/image_stacks.go
Normal file
81
backend/.gen/haystack/haystack/table/image_stacks.go
Normal file
@ -0,0 +1,81 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/postgres"
|
||||
)
|
||||
|
||||
var ImageStacks = newImageStacksTable("haystack", "image_stacks", "")
|
||||
|
||||
type imageStacksTable struct {
|
||||
postgres.Table
|
||||
|
||||
// Columns
|
||||
ID postgres.ColumnString
|
||||
ImageID postgres.ColumnString
|
||||
StackID postgres.ColumnString
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type ImageStacksTable struct {
|
||||
imageStacksTable
|
||||
|
||||
EXCLUDED imageStacksTable
|
||||
}
|
||||
|
||||
// AS creates new ImageStacksTable with assigned alias
|
||||
func (a ImageStacksTable) AS(alias string) *ImageStacksTable {
|
||||
return newImageStacksTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new ImageStacksTable with assigned schema name
|
||||
func (a ImageStacksTable) FromSchema(schemaName string) *ImageStacksTable {
|
||||
return newImageStacksTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
// WithPrefix creates new ImageStacksTable with assigned table prefix
|
||||
func (a ImageStacksTable) WithPrefix(prefix string) *ImageStacksTable {
|
||||
return newImageStacksTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||
}
|
||||
|
||||
// WithSuffix creates new ImageStacksTable with assigned table suffix
|
||||
func (a ImageStacksTable) WithSuffix(suffix string) *ImageStacksTable {
|
||||
return newImageStacksTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||
}
|
||||
|
||||
func newImageStacksTable(schemaName, tableName, alias string) *ImageStacksTable {
|
||||
return &ImageStacksTable{
|
||||
imageStacksTable: newImageStacksTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newImageStacksTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newImageStacksTableImpl(schemaName, tableName, alias string) imageStacksTable {
|
||||
var (
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
ImageIDColumn = postgres.StringColumn("image_id")
|
||||
StackIDColumn = postgres.StringColumn("stack_id")
|
||||
allColumns = postgres.ColumnList{IDColumn, ImageIDColumn, StackIDColumn}
|
||||
mutableColumns = postgres.ColumnList{ImageIDColumn, StackIDColumn}
|
||||
)
|
||||
|
||||
return imageStacksTable{
|
||||
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
ID: IDColumn,
|
||||
ImageID: ImageIDColumn,
|
||||
StackID: StackIDColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/postgres"
|
||||
)
|
||||
|
||||
var Lists = newListsTable("haystack", "lists", "")
|
||||
|
||||
type listsTable struct {
|
||||
postgres.Table
|
||||
|
||||
// Columns
|
||||
ID postgres.ColumnString
|
||||
UserID postgres.ColumnString
|
||||
Name postgres.ColumnString
|
||||
Description postgres.ColumnString
|
||||
CreatedAt postgres.ColumnTimestampz
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type ListsTable struct {
|
||||
listsTable
|
||||
|
||||
EXCLUDED listsTable
|
||||
}
|
||||
|
||||
// AS creates new ListsTable with assigned alias
|
||||
func (a ListsTable) AS(alias string) *ListsTable {
|
||||
return newListsTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new ListsTable with assigned schema name
|
||||
func (a ListsTable) FromSchema(schemaName string) *ListsTable {
|
||||
return newListsTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
// WithPrefix creates new ListsTable with assigned table prefix
|
||||
func (a ListsTable) WithPrefix(prefix string) *ListsTable {
|
||||
return newListsTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||
}
|
||||
|
||||
// WithSuffix creates new ListsTable with assigned table suffix
|
||||
func (a ListsTable) WithSuffix(suffix string) *ListsTable {
|
||||
return newListsTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||
}
|
||||
|
||||
func newListsTable(schemaName, tableName, alias string) *ListsTable {
|
||||
return &ListsTable{
|
||||
listsTable: newListsTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newListsTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newListsTableImpl(schemaName, tableName, alias string) listsTable {
|
||||
var (
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
UserIDColumn = postgres.StringColumn("user_id")
|
||||
NameColumn = postgres.StringColumn("name")
|
||||
DescriptionColumn = postgres.StringColumn("description")
|
||||
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||
allColumns = postgres.ColumnList{IDColumn, UserIDColumn, NameColumn, DescriptionColumn, CreatedAtColumn}
|
||||
mutableColumns = postgres.ColumnList{UserIDColumn, NameColumn, DescriptionColumn, CreatedAtColumn}
|
||||
defaultColumns = postgres.ColumnList{IDColumn, CreatedAtColumn}
|
||||
)
|
||||
|
||||
return listsTable{
|
||||
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
ID: IDColumn,
|
||||
UserID: UserIDColumn,
|
||||
Name: NameColumn,
|
||||
Description: DescriptionColumn,
|
||||
CreatedAt: CreatedAtColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/postgres"
|
||||
)
|
||||
|
||||
var Logs = newLogsTable("haystack", "logs", "")
|
||||
|
||||
type logsTable struct {
|
||||
postgres.Table
|
||||
|
||||
// Columns
|
||||
Log postgres.ColumnString
|
||||
ImageID postgres.ColumnString
|
||||
CreatedAt postgres.ColumnTimestampz
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type LogsTable struct {
|
||||
logsTable
|
||||
|
||||
EXCLUDED logsTable
|
||||
}
|
||||
|
||||
// AS creates new LogsTable with assigned alias
|
||||
func (a LogsTable) AS(alias string) *LogsTable {
|
||||
return newLogsTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new LogsTable with assigned schema name
|
||||
func (a LogsTable) FromSchema(schemaName string) *LogsTable {
|
||||
return newLogsTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
// WithPrefix creates new LogsTable with assigned table prefix
|
||||
func (a LogsTable) WithPrefix(prefix string) *LogsTable {
|
||||
return newLogsTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||
}
|
||||
|
||||
// WithSuffix creates new LogsTable with assigned table suffix
|
||||
func (a LogsTable) WithSuffix(suffix string) *LogsTable {
|
||||
return newLogsTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||
}
|
||||
|
||||
func newLogsTable(schemaName, tableName, alias string) *LogsTable {
|
||||
return &LogsTable{
|
||||
logsTable: newLogsTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newLogsTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newLogsTableImpl(schemaName, tableName, alias string) logsTable {
|
||||
var (
|
||||
LogColumn = postgres.StringColumn("log")
|
||||
ImageIDColumn = postgres.StringColumn("image_id")
|
||||
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||
allColumns = postgres.ColumnList{LogColumn, ImageIDColumn, CreatedAtColumn}
|
||||
mutableColumns = postgres.ColumnList{LogColumn, ImageIDColumn, CreatedAtColumn}
|
||||
defaultColumns = postgres.ColumnList{CreatedAtColumn}
|
||||
)
|
||||
|
||||
return logsTable{
|
||||
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
Log: LogColumn,
|
||||
ImageID: ImageIDColumn,
|
||||
CreatedAt: CreatedAtColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/postgres"
|
||||
)
|
||||
|
||||
var ProcessingLists = newProcessingListsTable("haystack", "processing_lists", "")
|
||||
|
||||
type processingListsTable struct {
|
||||
postgres.Table
|
||||
|
||||
// Columns
|
||||
ID postgres.ColumnString
|
||||
UserID postgres.ColumnString
|
||||
Title postgres.ColumnString
|
||||
Fields postgres.ColumnString
|
||||
Status postgres.ColumnString
|
||||
CreatedAt postgres.ColumnTimestampz
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type ProcessingListsTable struct {
|
||||
processingListsTable
|
||||
|
||||
EXCLUDED processingListsTable
|
||||
}
|
||||
|
||||
// AS creates new ProcessingListsTable with assigned alias
|
||||
func (a ProcessingListsTable) AS(alias string) *ProcessingListsTable {
|
||||
return newProcessingListsTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new ProcessingListsTable with assigned schema name
|
||||
func (a ProcessingListsTable) FromSchema(schemaName string) *ProcessingListsTable {
|
||||
return newProcessingListsTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
// WithPrefix creates new ProcessingListsTable with assigned table prefix
|
||||
func (a ProcessingListsTable) WithPrefix(prefix string) *ProcessingListsTable {
|
||||
return newProcessingListsTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||
}
|
||||
|
||||
// WithSuffix creates new ProcessingListsTable with assigned table suffix
|
||||
func (a ProcessingListsTable) WithSuffix(suffix string) *ProcessingListsTable {
|
||||
return newProcessingListsTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||
}
|
||||
|
||||
func newProcessingListsTable(schemaName, tableName, alias string) *ProcessingListsTable {
|
||||
return &ProcessingListsTable{
|
||||
processingListsTable: newProcessingListsTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newProcessingListsTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newProcessingListsTableImpl(schemaName, tableName, alias string) processingListsTable {
|
||||
var (
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
UserIDColumn = postgres.StringColumn("user_id")
|
||||
TitleColumn = postgres.StringColumn("title")
|
||||
FieldsColumn = postgres.StringColumn("fields")
|
||||
StatusColumn = postgres.StringColumn("status")
|
||||
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||
allColumns = postgres.ColumnList{IDColumn, UserIDColumn, TitleColumn, FieldsColumn, StatusColumn, CreatedAtColumn}
|
||||
mutableColumns = postgres.ColumnList{UserIDColumn, TitleColumn, FieldsColumn, StatusColumn, CreatedAtColumn}
|
||||
defaultColumns = postgres.ColumnList{IDColumn, StatusColumn, CreatedAtColumn}
|
||||
)
|
||||
|
||||
return processingListsTable{
|
||||
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
ID: IDColumn,
|
||||
UserID: UserIDColumn,
|
||||
Title: TitleColumn,
|
||||
Fields: FieldsColumn,
|
||||
Status: StatusColumn,
|
||||
CreatedAt: CreatedAtColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
@ -21,11 +21,10 @@ type schemaItemsTable struct {
|
||||
Item postgres.ColumnString
|
||||
Value postgres.ColumnString
|
||||
Description postgres.ColumnString
|
||||
SchemaID postgres.ColumnString
|
||||
StackID postgres.ColumnString
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type SchemaItemsTable struct {
|
||||
@ -67,10 +66,9 @@ func newSchemaItemsTableImpl(schemaName, tableName, alias string) schemaItemsTab
|
||||
ItemColumn = postgres.StringColumn("item")
|
||||
ValueColumn = postgres.StringColumn("value")
|
||||
DescriptionColumn = postgres.StringColumn("description")
|
||||
SchemaIDColumn = postgres.StringColumn("schema_id")
|
||||
allColumns = postgres.ColumnList{IDColumn, ItemColumn, ValueColumn, DescriptionColumn, SchemaIDColumn}
|
||||
mutableColumns = postgres.ColumnList{ItemColumn, ValueColumn, DescriptionColumn, SchemaIDColumn}
|
||||
defaultColumns = postgres.ColumnList{IDColumn}
|
||||
StackIDColumn = postgres.StringColumn("stack_id")
|
||||
allColumns = postgres.ColumnList{IDColumn, ItemColumn, ValueColumn, DescriptionColumn, StackIDColumn}
|
||||
mutableColumns = postgres.ColumnList{ItemColumn, ValueColumn, DescriptionColumn, StackIDColumn}
|
||||
)
|
||||
|
||||
return schemaItemsTable{
|
||||
@ -81,10 +79,9 @@ func newSchemaItemsTableImpl(schemaName, tableName, alias string) schemaItemsTab
|
||||
Item: ItemColumn,
|
||||
Value: ValueColumn,
|
||||
Description: DescriptionColumn,
|
||||
SchemaID: SchemaIDColumn,
|
||||
StackID: StackIDColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
||||
|
@ -1,81 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/postgres"
|
||||
)
|
||||
|
||||
var Schemas = newSchemasTable("haystack", "schemas", "")
|
||||
|
||||
type schemasTable struct {
|
||||
postgres.Table
|
||||
|
||||
// Columns
|
||||
ID postgres.ColumnString
|
||||
ListID postgres.ColumnString
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type SchemasTable struct {
|
||||
schemasTable
|
||||
|
||||
EXCLUDED schemasTable
|
||||
}
|
||||
|
||||
// AS creates new SchemasTable with assigned alias
|
||||
func (a SchemasTable) AS(alias string) *SchemasTable {
|
||||
return newSchemasTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new SchemasTable with assigned schema name
|
||||
func (a SchemasTable) FromSchema(schemaName string) *SchemasTable {
|
||||
return newSchemasTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
// WithPrefix creates new SchemasTable with assigned table prefix
|
||||
func (a SchemasTable) WithPrefix(prefix string) *SchemasTable {
|
||||
return newSchemasTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||
}
|
||||
|
||||
// WithSuffix creates new SchemasTable with assigned table suffix
|
||||
func (a SchemasTable) WithSuffix(suffix string) *SchemasTable {
|
||||
return newSchemasTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||
}
|
||||
|
||||
func newSchemasTable(schemaName, tableName, alias string) *SchemasTable {
|
||||
return &SchemasTable{
|
||||
schemasTable: newSchemasTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newSchemasTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newSchemasTableImpl(schemaName, tableName, alias string) schemasTable {
|
||||
var (
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
ListIDColumn = postgres.StringColumn("list_id")
|
||||
allColumns = postgres.ColumnList{IDColumn, ListIDColumn}
|
||||
mutableColumns = postgres.ColumnList{ListIDColumn}
|
||||
defaultColumns = postgres.ColumnList{IDColumn}
|
||||
)
|
||||
|
||||
return schemasTable{
|
||||
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
ID: IDColumn,
|
||||
ListID: ListIDColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
90
backend/.gen/haystack/haystack/table/stacks.go
Normal file
90
backend/.gen/haystack/haystack/table/stacks.go
Normal file
@ -0,0 +1,90 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/postgres"
|
||||
)
|
||||
|
||||
var Stacks = newStacksTable("haystack", "stacks", "")
|
||||
|
||||
type stacksTable struct {
|
||||
postgres.Table
|
||||
|
||||
// Columns
|
||||
ID postgres.ColumnString
|
||||
UserID postgres.ColumnString
|
||||
Status postgres.ColumnString
|
||||
Name postgres.ColumnString
|
||||
Description postgres.ColumnString
|
||||
CreatedAt postgres.ColumnTimestampz
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type StacksTable struct {
|
||||
stacksTable
|
||||
|
||||
EXCLUDED stacksTable
|
||||
}
|
||||
|
||||
// AS creates new StacksTable with assigned alias
|
||||
func (a StacksTable) AS(alias string) *StacksTable {
|
||||
return newStacksTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new StacksTable with assigned schema name
|
||||
func (a StacksTable) FromSchema(schemaName string) *StacksTable {
|
||||
return newStacksTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
// WithPrefix creates new StacksTable with assigned table prefix
|
||||
func (a StacksTable) WithPrefix(prefix string) *StacksTable {
|
||||
return newStacksTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||
}
|
||||
|
||||
// WithSuffix creates new StacksTable with assigned table suffix
|
||||
func (a StacksTable) WithSuffix(suffix string) *StacksTable {
|
||||
return newStacksTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||
}
|
||||
|
||||
func newStacksTable(schemaName, tableName, alias string) *StacksTable {
|
||||
return &StacksTable{
|
||||
stacksTable: newStacksTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newStacksTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newStacksTableImpl(schemaName, tableName, alias string) stacksTable {
|
||||
var (
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
UserIDColumn = postgres.StringColumn("user_id")
|
||||
StatusColumn = postgres.StringColumn("status")
|
||||
NameColumn = postgres.StringColumn("name")
|
||||
DescriptionColumn = postgres.StringColumn("description")
|
||||
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||
allColumns = postgres.ColumnList{IDColumn, UserIDColumn, StatusColumn, NameColumn, DescriptionColumn, CreatedAtColumn}
|
||||
mutableColumns = postgres.ColumnList{UserIDColumn, StatusColumn, NameColumn, DescriptionColumn, CreatedAtColumn}
|
||||
)
|
||||
|
||||
return stacksTable{
|
||||
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
ID: IDColumn,
|
||||
UserID: UserIDColumn,
|
||||
Status: StatusColumn,
|
||||
Name: NameColumn,
|
||||
Description: DescriptionColumn,
|
||||
CreatedAt: CreatedAtColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
}
|
||||
}
|
@ -11,14 +11,9 @@ package table
|
||||
// this method only once at the beginning of the program.
|
||||
func UseSchema(schema string) {
|
||||
Image = Image.FromSchema(schema)
|
||||
ImageLists = ImageLists.FromSchema(schema)
|
||||
ImageSchemaItems = ImageSchemaItems.FromSchema(schema)
|
||||
Lists = Lists.FromSchema(schema)
|
||||
Logs = Logs.FromSchema(schema)
|
||||
ProcessingLists = ProcessingLists.FromSchema(schema)
|
||||
ImageStacks = ImageStacks.FromSchema(schema)
|
||||
SchemaItems = SchemaItems.FromSchema(schema)
|
||||
Schemas = Schemas.FromSchema(schema)
|
||||
UserImages = UserImages.FromSchema(schema)
|
||||
UserImagesToProcess = UserImagesToProcess.FromSchema(schema)
|
||||
Stacks = Stacks.FromSchema(schema)
|
||||
Users = Users.FromSchema(schema)
|
||||
}
|
||||
|
@ -1,87 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/postgres"
|
||||
)
|
||||
|
||||
var UserImages = newUserImagesTable("haystack", "user_images", "")
|
||||
|
||||
type userImagesTable struct {
|
||||
postgres.Table
|
||||
|
||||
// Columns
|
||||
ID postgres.ColumnString
|
||||
ImageID postgres.ColumnString
|
||||
UserID postgres.ColumnString
|
||||
CreatedAt postgres.ColumnTimestampz
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type UserImagesTable struct {
|
||||
userImagesTable
|
||||
|
||||
EXCLUDED userImagesTable
|
||||
}
|
||||
|
||||
// AS creates new UserImagesTable with assigned alias
|
||||
func (a UserImagesTable) AS(alias string) *UserImagesTable {
|
||||
return newUserImagesTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new UserImagesTable with assigned schema name
|
||||
func (a UserImagesTable) FromSchema(schemaName string) *UserImagesTable {
|
||||
return newUserImagesTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
// WithPrefix creates new UserImagesTable with assigned table prefix
|
||||
func (a UserImagesTable) WithPrefix(prefix string) *UserImagesTable {
|
||||
return newUserImagesTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||
}
|
||||
|
||||
// WithSuffix creates new UserImagesTable with assigned table suffix
|
||||
func (a UserImagesTable) WithSuffix(suffix string) *UserImagesTable {
|
||||
return newUserImagesTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||
}
|
||||
|
||||
func newUserImagesTable(schemaName, tableName, alias string) *UserImagesTable {
|
||||
return &UserImagesTable{
|
||||
userImagesTable: newUserImagesTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newUserImagesTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newUserImagesTableImpl(schemaName, tableName, alias string) userImagesTable {
|
||||
var (
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
ImageIDColumn = postgres.StringColumn("image_id")
|
||||
UserIDColumn = postgres.StringColumn("user_id")
|
||||
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||
allColumns = postgres.ColumnList{IDColumn, ImageIDColumn, UserIDColumn, CreatedAtColumn}
|
||||
mutableColumns = postgres.ColumnList{ImageIDColumn, UserIDColumn, CreatedAtColumn}
|
||||
defaultColumns = postgres.ColumnList{IDColumn, CreatedAtColumn}
|
||||
)
|
||||
|
||||
return userImagesTable{
|
||||
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
ID: IDColumn,
|
||||
ImageID: ImageIDColumn,
|
||||
UserID: UserIDColumn,
|
||||
CreatedAt: CreatedAtColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
//
|
||||
// Code generated by go-jet DO NOT EDIT.
|
||||
//
|
||||
// WARNING: Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated
|
||||
//
|
||||
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/go-jet/jet/v2/postgres"
|
||||
)
|
||||
|
||||
var UserImagesToProcess = newUserImagesToProcessTable("haystack", "user_images_to_process", "")
|
||||
|
||||
type userImagesToProcessTable struct {
|
||||
postgres.Table
|
||||
|
||||
// Columns
|
||||
ID postgres.ColumnString
|
||||
Status postgres.ColumnString
|
||||
ImageID postgres.ColumnString
|
||||
UserID postgres.ColumnString
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type UserImagesToProcessTable struct {
|
||||
userImagesToProcessTable
|
||||
|
||||
EXCLUDED userImagesToProcessTable
|
||||
}
|
||||
|
||||
// AS creates new UserImagesToProcessTable with assigned alias
|
||||
func (a UserImagesToProcessTable) AS(alias string) *UserImagesToProcessTable {
|
||||
return newUserImagesToProcessTable(a.SchemaName(), a.TableName(), alias)
|
||||
}
|
||||
|
||||
// Schema creates new UserImagesToProcessTable with assigned schema name
|
||||
func (a UserImagesToProcessTable) FromSchema(schemaName string) *UserImagesToProcessTable {
|
||||
return newUserImagesToProcessTable(schemaName, a.TableName(), a.Alias())
|
||||
}
|
||||
|
||||
// WithPrefix creates new UserImagesToProcessTable with assigned table prefix
|
||||
func (a UserImagesToProcessTable) WithPrefix(prefix string) *UserImagesToProcessTable {
|
||||
return newUserImagesToProcessTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
|
||||
}
|
||||
|
||||
// WithSuffix creates new UserImagesToProcessTable with assigned table suffix
|
||||
func (a UserImagesToProcessTable) WithSuffix(suffix string) *UserImagesToProcessTable {
|
||||
return newUserImagesToProcessTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
|
||||
}
|
||||
|
||||
func newUserImagesToProcessTable(schemaName, tableName, alias string) *UserImagesToProcessTable {
|
||||
return &UserImagesToProcessTable{
|
||||
userImagesToProcessTable: newUserImagesToProcessTableImpl(schemaName, tableName, alias),
|
||||
EXCLUDED: newUserImagesToProcessTableImpl("", "excluded", ""),
|
||||
}
|
||||
}
|
||||
|
||||
func newUserImagesToProcessTableImpl(schemaName, tableName, alias string) userImagesToProcessTable {
|
||||
var (
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
StatusColumn = postgres.StringColumn("status")
|
||||
ImageIDColumn = postgres.StringColumn("image_id")
|
||||
UserIDColumn = postgres.StringColumn("user_id")
|
||||
allColumns = postgres.ColumnList{IDColumn, StatusColumn, ImageIDColumn, UserIDColumn}
|
||||
mutableColumns = postgres.ColumnList{StatusColumn, ImageIDColumn, UserIDColumn}
|
||||
defaultColumns = postgres.ColumnList{IDColumn, StatusColumn}
|
||||
)
|
||||
|
||||
return userImagesToProcessTable{
|
||||
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
ID: IDColumn,
|
||||
Status: StatusColumn,
|
||||
ImageID: ImageIDColumn,
|
||||
UserID: UserIDColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
@ -17,12 +17,12 @@ type usersTable struct {
|
||||
postgres.Table
|
||||
|
||||
// Columns
|
||||
ID postgres.ColumnString
|
||||
Email postgres.ColumnString
|
||||
ID postgres.ColumnString
|
||||
Email postgres.ColumnString
|
||||
CreatedAt postgres.ColumnTimestampz
|
||||
|
||||
AllColumns postgres.ColumnList
|
||||
MutableColumns postgres.ColumnList
|
||||
DefaultColumns postgres.ColumnList
|
||||
}
|
||||
|
||||
type UsersTable struct {
|
||||
@ -60,22 +60,22 @@ func newUsersTable(schemaName, tableName, alias string) *UsersTable {
|
||||
|
||||
func newUsersTableImpl(schemaName, tableName, alias string) usersTable {
|
||||
var (
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
EmailColumn = postgres.StringColumn("email")
|
||||
allColumns = postgres.ColumnList{IDColumn, EmailColumn}
|
||||
mutableColumns = postgres.ColumnList{EmailColumn}
|
||||
defaultColumns = postgres.ColumnList{IDColumn}
|
||||
IDColumn = postgres.StringColumn("id")
|
||||
EmailColumn = postgres.StringColumn("email")
|
||||
CreatedAtColumn = postgres.TimestampzColumn("created_at")
|
||||
allColumns = postgres.ColumnList{IDColumn, EmailColumn, CreatedAtColumn}
|
||||
mutableColumns = postgres.ColumnList{EmailColumn, CreatedAtColumn}
|
||||
)
|
||||
|
||||
return usersTable{
|
||||
Table: postgres.NewTable(schemaName, tableName, alias, allColumns...),
|
||||
|
||||
//Columns
|
||||
ID: IDColumn,
|
||||
Email: EmailColumn,
|
||||
ID: IDColumn,
|
||||
Email: EmailColumn,
|
||||
CreatedAt: CreatedAtColumn,
|
||||
|
||||
AllColumns: allColumns,
|
||||
MutableColumns: mutableColumns,
|
||||
DefaultColumns: defaultColumns,
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ type createNewListArguments struct {
|
||||
type CreateListAgent struct {
|
||||
client client.AgentClient
|
||||
|
||||
listModel models.ListModel
|
||||
listModel models.StackModel
|
||||
}
|
||||
|
||||
func (agent *CreateListAgent) CreateList(log *log.Logger, userID uuid.UUID, userReq string) error {
|
||||
@ -120,12 +120,20 @@ func (agent *CreateListAgent) CreateList(log *log.Logger, userID uuid.UUID, user
|
||||
})
|
||||
}
|
||||
|
||||
agent.listModel.Save(ctx, userID, createListArgs.Title, createListArgs.Description, schemaItems)
|
||||
_, err = agent.listModel.Save(ctx, userID, createListArgs.Title, createListArgs.Description)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating list agent, saving list: %w", err)
|
||||
}
|
||||
|
||||
err = agent.listModel.SaveItems(ctx, schemaItems)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating list agent, saving items: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewCreateListAgent(log *log.Logger, listModel models.ListModel) CreateListAgent {
|
||||
func NewCreateListAgent(log *log.Logger, listModel models.StackModel) CreateListAgent {
|
||||
client := client.CreateAgentClient(client.CreateAgentClientOptions{
|
||||
SystemPrompt: createListAgentPrompt,
|
||||
Log: log,
|
||||
|
@ -3,6 +3,7 @@ package agents
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||
"screenmark/screenmark/agents/client"
|
||||
"screenmark/screenmark/models"
|
||||
|
||||
@ -26,7 +27,7 @@ type DescriptionAgent struct {
|
||||
imageModel models.ImageModel
|
||||
}
|
||||
|
||||
func (agent DescriptionAgent) Describe(log *log.Logger, imageId uuid.UUID, imageName string, imageData []byte) error {
|
||||
func (agent DescriptionAgent) Describe(log *log.Logger, imageID uuid.UUID, imageName string, imageData []byte) error {
|
||||
request := client.AgentRequestBody{
|
||||
Model: "policy/images",
|
||||
Temperature: 0.3,
|
||||
@ -51,7 +52,11 @@ func (agent DescriptionAgent) Describe(log *log.Logger, imageId uuid.UUID, image
|
||||
|
||||
markdown := resp.Choices[0].Message.Content
|
||||
|
||||
err = agent.imageModel.AddDescription(ctx, imageId, markdown)
|
||||
_, err = agent.imageModel.Update(ctx, model.Image{
|
||||
ID: imageID,
|
||||
Description: markdown,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ type addToListArguments struct {
|
||||
Schema []models.IDValue
|
||||
}
|
||||
|
||||
func NewListAgent(log *log.Logger, listModel models.ListModel, limitsMethods limits.LimitsManagerMethods) client.AgentClient {
|
||||
func NewListAgent(log *log.Logger, listModel models.StackModel, limitsMethods limits.LimitsManagerMethods) client.AgentClient {
|
||||
agentClient := client.CreateAgentClient(client.CreateAgentClientOptions{
|
||||
SystemPrompt: listPrompt,
|
||||
JsonTools: listTools,
|
||||
@ -206,10 +206,19 @@ func NewListAgent(log *log.Logger, listModel models.ListModel, limitsMethods lim
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
savedList, err := listModel.Save(ctx, info.UserId, args.Name, args.Desription, args.Schema)
|
||||
|
||||
savedList, err := listModel.Save(ctx, info.UserId, args.Name, args.Desription)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Error("saving list", "err", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
for i := range args.Schema {
|
||||
args.Schema[i].StackID = savedList.ID
|
||||
}
|
||||
|
||||
err = listModel.SaveItems(ctx, args.Schema)
|
||||
if err != nil {
|
||||
log.Error("saving items", "err", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
@ -229,12 +238,12 @@ func NewListAgent(log *log.Logger, listModel models.ListModel, limitsMethods lim
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
listUuid, err := uuid.Parse(args.ListID)
|
||||
listUUID, err := uuid.Parse(args.ListID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := listModel.SaveInto(ctx, listUuid, info.ImageId, args.Schema); err != nil {
|
||||
if err := listModel.SaveImage(ctx, info.ImageId, listUUID); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"screenmark/screenmark/agents"
|
||||
"screenmark/screenmark/limits"
|
||||
"screenmark/screenmark/middleware"
|
||||
"screenmark/screenmark/models"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/google/uuid"
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -76,229 +66,6 @@ func (n *Notification) UnmarshalJSON(data []byte) error {
|
||||
return fmt.Errorf("unimplemented")
|
||||
}
|
||||
|
||||
func ProcessImage(log *log.Logger, db *sql.DB) func(imageID uuid.UUID) {
|
||||
imageModel := models.NewImageModel(db)
|
||||
listModel := models.NewListModel(db)
|
||||
limits := limits.CreateLimitsManager(db)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
return func(imageID uuid.UUID) {
|
||||
log.Debug("Starting processing image", "ImageID", imageID)
|
||||
|
||||
go func() {
|
||||
image, err := imageModel.GetToProcessWithData(ctx, imageID)
|
||||
if err != nil {
|
||||
log.Error("Failed to GetToProcessWithData", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
splitWriter := createDbStdoutWriter(db, image.ImageID)
|
||||
|
||||
if err := imageModel.StartProcessing(ctx, image.ID); err != nil {
|
||||
log.Error("Failed to FinishProcessing", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
descriptionAgent := agents.NewDescriptionAgent(createLogger("Description 📝", splitWriter), imageModel)
|
||||
listAgent := agents.NewListAgent(createLogger("Lists 🖋️", splitWriter), listModel, limits)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
descriptionAgent.Describe(createLogger("Description 📓", splitWriter), image.Image.ID, image.Image.ImageName, image.Image.Image)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
listAgent.RunAgent(image.UserID, image.ImageID, image.Image.ImageName, image.Image.Image)
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
_, err = imageModel.FinishProcessing(ctx, image.ID)
|
||||
if err != nil {
|
||||
log.Error("Failed to finish processing", "ImageID", imageID, "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debug("Finished processing image", "ImageID", imageID)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func ListenNewImageEvents(db *sql.DB) {
|
||||
listener := pq.NewListener(os.Getenv("DB_CONNECTION"), time.Second, time.Second, func(event pq.ListenerEventType, err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
defer listener.Close()
|
||||
|
||||
databaseEventLog := createLogger("Database Events 🤖", os.Stdout)
|
||||
databaseEventLog.SetLevel(log.DebugLevel)
|
||||
|
||||
err := listener.Listen("new_image")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for parameters := range listener.Notify {
|
||||
imageID := uuid.MustParse(parameters.Extra)
|
||||
ProcessImage(databaseEventLog, db)(imageID)
|
||||
}
|
||||
}
|
||||
|
||||
func ListenProcessingImageStatus(db *sql.DB, images models.ImageModel, notifier *Notifier[Notification]) {
|
||||
listener := pq.NewListener(os.Getenv("DB_CONNECTION"), time.Second, time.Second, func(event pq.ListenerEventType, err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
defer listener.Close()
|
||||
|
||||
logger := createLogger("Image Status 📊", os.Stdout)
|
||||
|
||||
if err := listener.Listen("new_processing_image_status"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for data := range listener.Notify {
|
||||
imageStringUuid := data.Extra[0:36]
|
||||
status := data.Extra[36:]
|
||||
|
||||
imageUuid, err := uuid.Parse(imageStringUuid)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
processingImage, err := images.GetToProcess(context.Background(), imageUuid)
|
||||
if err != nil {
|
||||
logger.Error("GetToProcess failed", "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Info("Update", "id", imageStringUuid, "status", status)
|
||||
|
||||
notification := getImageNotification(imageNotification{
|
||||
Type: IMAGE_TYPE,
|
||||
ImageID: processingImage.ImageID,
|
||||
ImageName: processingImage.Image.ImageName,
|
||||
Status: status,
|
||||
})
|
||||
|
||||
if err := notifier.SendAndCreate(processingImage.UserID.String(), notification); err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ListenNewStackEvents(db *sql.DB) {
|
||||
listener := pq.NewListener(os.Getenv("DB_CONNECTION"), time.Second, time.Second, func(event pq.ListenerEventType, err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
defer listener.Close()
|
||||
|
||||
stackModel := models.NewListModel(db)
|
||||
|
||||
newStacksLogger := createLogger("New Stacks 🤖", os.Stdout)
|
||||
newStacksLogger.SetLevel(log.DebugLevel)
|
||||
|
||||
err := listener.Listen("new_stack")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for parameters := range listener.Notify {
|
||||
stackID := uuid.MustParse(parameters.Extra)
|
||||
|
||||
newStacksLogger.Debug("Starting processing stack", "StackID", stackID)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
go func() {
|
||||
stack, err := stackModel.GetProcessing(ctx, stackID)
|
||||
if err != nil {
|
||||
newStacksLogger.Error("failed to get processing", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := stackModel.StartProcessing(ctx, stackID); err != nil {
|
||||
newStacksLogger.Error("failed to start processing", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
listAgent := agents.NewCreateListAgent(newStacksLogger, stackModel)
|
||||
userListRequest := fmt.Sprintf("title=%s,fields=%s", stack.Title, stack.Fields)
|
||||
|
||||
err = listAgent.CreateList(newStacksLogger, stack.UserID, userListRequest)
|
||||
if err != nil {
|
||||
newStacksLogger.Error("running agent", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := stackModel.EndProcessing(ctx, stackID); err != nil {
|
||||
newStacksLogger.Error("failed to finish processing", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
newStacksLogger.Debug("Finished processing stack", "StackID", stackID)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func ListenProcessingStackStatus(db *sql.DB, stacks models.ListModel, notifier *Notifier[Notification]) {
|
||||
listener := pq.NewListener(os.Getenv("DB_CONNECTION"), time.Second, time.Second, func(event pq.ListenerEventType, err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
defer listener.Close()
|
||||
|
||||
logger := createLogger("Stack Status 📊", os.Stdout)
|
||||
|
||||
if err := listener.Listen("new_processing_stack_status"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for data := range listener.Notify {
|
||||
stackStringUUID := data.Extra[0:36]
|
||||
status := data.Extra[36:]
|
||||
|
||||
stackUUID, err := uuid.Parse(stackStringUUID)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
processingStack, err := stacks.GetToProcess(context.Background(), stackUUID)
|
||||
if err != nil {
|
||||
logger.Error("GetToProcess failed", "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Info("Update", "id", stackStringUUID, "status", status)
|
||||
|
||||
notification := getListNotification(listNotification{
|
||||
Type: LIST_TYPE,
|
||||
Name: processingStack.Title,
|
||||
ListID: stackUUID,
|
||||
Status: status,
|
||||
})
|
||||
|
||||
if err := notifier.SendAndCreate(processingStack.UserID.String(), notification); err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: We have channels open every a user sends an image.
|
||||
* We never close these channels.
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||
"screenmark/screenmark/limits"
|
||||
"screenmark/screenmark/middleware"
|
||||
"screenmark/screenmark/models"
|
||||
@ -27,15 +26,12 @@ type ImageHandler struct {
|
||||
|
||||
limitsManager limits.LimitsManagerMethods
|
||||
|
||||
processImage func(imageID uuid.UUID)
|
||||
|
||||
jwtManager *middleware.JwtManager
|
||||
}
|
||||
|
||||
type ImagesReturn struct {
|
||||
UserImages []models.UserImageWithImage `json:"userImages"`
|
||||
ProcessingImages []models.UserProcessingImage `json:"processingImages"`
|
||||
Lists []models.ListsWithImages `json:"lists"`
|
||||
UserImages []models.UserImageWithImage `json:"userImages"`
|
||||
Lists []models.ListsWithImages `json:"lists"`
|
||||
}
|
||||
|
||||
func (h *ImageHandler) serveImage(w http.ResponseWriter, r *http.Request) {
|
||||
@ -52,19 +48,19 @@ func (h *ImageHandler) serveImage(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
isAuthorized := h.imageModel.IsUserAuthorized(ctx, imageID, userID)
|
||||
if !isAuthorized {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
image, err := h.imageModel.Get(r.Context(), imageID)
|
||||
image, exists, err := h.imageModel.Get(r.Context(), imageID)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
fmt.Fprintf(w, "Could not get image")
|
||||
return
|
||||
}
|
||||
|
||||
// Do not leak that this ID exists.
|
||||
if !exists || *image.UserID != userID {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: this could be part of the db table
|
||||
extension := filepath.Ext(image.ImageName)
|
||||
if len(extension) == 0 {
|
||||
@ -89,12 +85,6 @@ func (h *ImageHandler) listImages(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
processingImages, err := h.imageModel.GetProcessing(r.Context(), userId)
|
||||
if err != nil {
|
||||
middleware.WriteErrorInternal(h.logger, "could not get processing images", w)
|
||||
return
|
||||
}
|
||||
|
||||
listsWithImages, err := h.userModel.ListWithImages(r.Context(), userId)
|
||||
if err != nil {
|
||||
middleware.WriteErrorInternal(h.logger, "could not get lists with images", w)
|
||||
@ -102,9 +92,8 @@ func (h *ImageHandler) listImages(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
imagesReturn := ImagesReturn{
|
||||
UserImages: images,
|
||||
ProcessingImages: processingImages,
|
||||
Lists: listsWithImages,
|
||||
UserImages: images,
|
||||
Lists: listsWithImages,
|
||||
}
|
||||
|
||||
middleware.WriteJsonOrError(h.logger, imagesReturn, w)
|
||||
@ -117,7 +106,7 @@ func (h *ImageHandler) uploadImage(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
userId, err := middleware.GetUserID(r.Context(), h.logger, w)
|
||||
userID, err := middleware.GetUserID(r.Context(), h.logger, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -151,17 +140,16 @@ func (h *ImageHandler) uploadImage(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
userImage, err := h.imageModel.Process(r.Context(), userId, model.Image{
|
||||
Image: image,
|
||||
ImageName: imageName,
|
||||
})
|
||||
ctx := r.Context()
|
||||
|
||||
err = h.imageModel.Save(ctx, imageName, image, userID)
|
||||
|
||||
if err != nil {
|
||||
middleware.WriteErrorInternal(h.logger, "could not save image to DB", w)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.WriteJsonOrError(h.logger, userImage, w)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (h *ImageHandler) deleteImage(w http.ResponseWriter, r *http.Request) {
|
||||
@ -180,71 +168,19 @@ func (h *ImageHandler) deleteImage(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
isAuthorized := h.imageModel.IsUserAuthorized(ctx, imageID, userID)
|
||||
if !isAuthorized {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.imageModel.Delete(ctx, imageID)
|
||||
exists, err := h.imageModel.Delete(ctx, imageID, userID)
|
||||
if err != nil {
|
||||
h.logger.Warn("cannot delete image", "error", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
// This feature is actually stupid
|
||||
func (h *ImageHandler) reprocessImage(w http.ResponseWriter, r *http.Request) {
|
||||
stringImageID := chi.URLParam(r, "image-id")
|
||||
imageID, err := uuid.Parse(stringImageID)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
// Don't leak if the image exists or not
|
||||
if !exists {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
userID, err := middleware.GetUserID(ctx, h.logger, w)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
isAuthorized := h.imageModel.IsUserAuthorized(ctx, imageID, userID)
|
||||
if !isAuthorized {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
imageToProcessID, err := h.imageModel.GetImageToProcessID(ctx, imageID)
|
||||
if err != nil {
|
||||
h.logger.Error("get image to process", "err", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// The whole way in which I do this event driven stuff is stupid.
|
||||
// It's so messy now
|
||||
|
||||
err = h.imageModel.DeleteUserImage(ctx, imageID)
|
||||
if err != nil {
|
||||
h.logger.Error("delete user image", "err", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.imageModel.SetNotStarted(ctx, imageToProcessID)
|
||||
if err != nil {
|
||||
h.logger.Error("set not started", "err", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
h.processImage(imageToProcessID)
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
@ -266,7 +202,7 @@ func (h *ImageHandler) CreateRoutes(r chi.Router) {
|
||||
})
|
||||
}
|
||||
|
||||
func CreateImageHandler(db *sql.DB, limitsManager limits.LimitsManagerMethods, processImage func(imageID uuid.UUID), jwtManager *middleware.JwtManager) ImageHandler {
|
||||
func CreateImageHandler(db *sql.DB, limitsManager limits.LimitsManagerMethods, jwtManager *middleware.JwtManager) ImageHandler {
|
||||
imageModel := models.NewImageModel(db)
|
||||
userModel := models.NewUserModel(db)
|
||||
logger := log.New(os.Stdout).WithPrefix("Images")
|
||||
@ -276,7 +212,6 @@ func CreateImageHandler(db *sql.DB, limitsManager limits.LimitsManagerMethods, p
|
||||
imageModel: imageModel,
|
||||
userModel: userModel,
|
||||
limitsManager: limitsManager,
|
||||
processImage: processImage,
|
||||
jwtManager: jwtManager,
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
|
||||
const (
|
||||
LISTS_LIMIT = 10
|
||||
IMAGE_LIMIT = 50
|
||||
IMAGE_LIMIT = 10
|
||||
)
|
||||
|
||||
type LimitsManager struct {
|
||||
@ -29,9 +29,9 @@ type listCount struct {
|
||||
}
|
||||
|
||||
func (m *LimitsManager) HasReachedStackLimit(userID uuid.UUID) (bool, error) {
|
||||
getStacks := Lists.
|
||||
SELECT(COUNT(Lists.UserID).AS("listCount.ListCount")).
|
||||
WHERE(Lists.UserID.EQ(UUID(userID)))
|
||||
getStacks := Stacks.
|
||||
SELECT(COUNT(Stacks.UserID).AS("listCount.ListCount")).
|
||||
WHERE(Stacks.UserID.EQ(UUID(userID)))
|
||||
|
||||
var count listCount
|
||||
err := getStacks.Query(m.dbPool, &count)
|
||||
@ -44,9 +44,9 @@ type imageCount struct {
|
||||
}
|
||||
|
||||
func (m *LimitsManager) HasReachedImageLimit(userID uuid.UUID) (bool, error) {
|
||||
getStacks := UserImages.
|
||||
SELECT(COUNT(UserImages.UserID).AS("imageCount.ImageCount")).
|
||||
WHERE(UserImages.UserID.EQ(UUID(userID)))
|
||||
getStacks := Image.
|
||||
SELECT(COUNT(Image.UserID).AS("imageCount.ImageCount")).
|
||||
WHERE(Image.UserID.EQ(UUID(userID)))
|
||||
|
||||
var count imageCount
|
||||
err := getStacks.Query(m.dbPool, &count)
|
||||
|
@ -1,21 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||
. "screenmark/screenmark/.gen/haystack/haystack/table"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
. "github.com/go-jet/jet/v2/postgres"
|
||||
"github.com/robert-nix/ansihtml"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/google/uuid"
|
||||
"github.com/muesli/termenv"
|
||||
@ -31,12 +21,6 @@ func (w *DatabaseWriter) Write(p []byte) (n int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
insertLogStmt := Logs.
|
||||
INSERT(Logs.Log, Logs.ImageID).
|
||||
VALUES(string(p), w.imageId)
|
||||
|
||||
_, err = insertLogStmt.Exec(w.dbPool)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
@ -44,85 +28,6 @@ func (w *DatabaseWriter) Write(p []byte) (n int, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *DatabaseWriter) GetImageLogs(ctx context.Context, imageId uuid.UUID) ([]string, error) {
|
||||
getImageLogsStmt := Logs.
|
||||
SELECT(Logs.Log).
|
||||
WHERE(Logs.ImageID.EQ(UUID(imageId)))
|
||||
|
||||
logs := []model.Logs{}
|
||||
err := getImageLogsStmt.QueryContext(ctx, w.dbPool, &logs)
|
||||
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
stringLogs := make([]string, len(logs))
|
||||
for i, log := range logs {
|
||||
stringLogs[i] = log.Log
|
||||
}
|
||||
|
||||
return stringLogs, nil
|
||||
}
|
||||
|
||||
func createLogHandler(logWriter *DatabaseWriter) func(r chi.Router) {
|
||||
return func(r chi.Router) {
|
||||
r.Get("/{imageId}", func(w http.ResponseWriter, r *http.Request) {
|
||||
stringImageId := r.PathValue("imageId")
|
||||
imageId, err := uuid.Parse(stringImageId)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
|
||||
logs, err := logWriter.GetImageLogs(r.Context(), imageId)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
html := ""
|
||||
|
||||
imageTag := fmt.Sprintf(`<image src="https://haystack.johncosta.tech/image/%s">`, stringImageId)
|
||||
|
||||
for _, log := range logs {
|
||||
html += fmt.Sprintf("<div>%s</div>", string(ansihtml.ConvertToHTML([]byte(log)))+"\n")
|
||||
}
|
||||
|
||||
css := `
|
||||
<style>
|
||||
body {
|
||||
background-color: #1e1e1e;
|
||||
color: #f0f0f0;
|
||||
font-family: sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* Basic styling for code blocks often used for logs */
|
||||
pre {
|
||||
background-color: #2a2a2a;
|
||||
padding: 1em;
|
||||
border-radius: 4px;
|
||||
overflow-x: auto;
|
||||
border: 1px solid #444;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
`
|
||||
|
||||
fullHtml := fmt.Sprintf("<html><head><title>Logs</title>%s</head><body>%s%s</body></html>", css, imageTag, html)
|
||||
|
||||
w.Header().Add("Content-Type", "text/html")
|
||||
w.Write([]byte(fullHtml))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newDatabaseWriter(dbPool *sql.DB, imageId uuid.UUID) *DatabaseWriter {
|
||||
return &DatabaseWriter{
|
||||
dbPool: dbPool,
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"screenmark/screenmark/.gen/haystack/haystack/enum"
|
||||
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||
. "screenmark/screenmark/.gen/haystack/haystack/table"
|
||||
|
||||
@ -18,248 +17,50 @@ type ImageModel struct {
|
||||
dbPool *sql.DB
|
||||
}
|
||||
|
||||
type ImageData struct {
|
||||
model.UserImages
|
||||
func (m ImageModel) Save(ctx context.Context, name string, image []byte, userID uuid.UUID) error {
|
||||
saveImageStmt := Image.INSERT(Image.ImageName, Image.Image, Image.UserID).
|
||||
VALUES(name, image, userID)
|
||||
|
||||
Image model.Image
|
||||
}
|
||||
|
||||
type ProcessingImageData struct {
|
||||
model.UserImagesToProcess
|
||||
|
||||
Image model.Image
|
||||
}
|
||||
|
||||
type UserProcessingImage struct {
|
||||
model.UserImagesToProcess
|
||||
|
||||
Image model.Image
|
||||
}
|
||||
|
||||
func (m ImageModel) Process(ctx context.Context, userId uuid.UUID, image model.Image) (model.UserImagesToProcess, error) {
|
||||
tx, err := m.dbPool.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return model.UserImagesToProcess{}, fmt.Errorf("Failed to begin transaction: %w", err)
|
||||
}
|
||||
|
||||
insertImageStmt := Image.
|
||||
INSERT(Image.ImageName, Image.Image, Image.Description).
|
||||
VALUES(image.ImageName, image.Image, image.Description).
|
||||
RETURNING(Image.ID)
|
||||
|
||||
insertedImage := model.Image{}
|
||||
err = insertImageStmt.QueryContext(ctx, tx, &insertedImage)
|
||||
if err != nil {
|
||||
return model.UserImagesToProcess{}, fmt.Errorf("Could not insert/query new image. SQL %s: %w", insertImageStmt.DebugSql(), err)
|
||||
}
|
||||
|
||||
stmt := UserImagesToProcess.
|
||||
INSERT(UserImagesToProcess.UserID, UserImagesToProcess.ImageID).
|
||||
VALUES(userId, insertedImage.ID).
|
||||
RETURNING(UserImagesToProcess.AllColumns)
|
||||
|
||||
userImage := model.UserImagesToProcess{}
|
||||
err = stmt.QueryContext(ctx, tx, &userImage)
|
||||
if err != nil {
|
||||
return model.UserImagesToProcess{}, fmt.Errorf("Could not insert user_image: %w", err)
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
|
||||
return userImage, err
|
||||
}
|
||||
|
||||
func (m ImageModel) GetToProcess(ctx context.Context, imageId uuid.UUID) (UserProcessingImage, error) {
|
||||
getToProcessStmt := SELECT(UserImagesToProcess.AllColumns, Image.ID, Image.ImageName).
|
||||
FROM(
|
||||
UserImagesToProcess.INNER_JOIN(
|
||||
Image, Image.ID.EQ(UserImagesToProcess.ImageID),
|
||||
),
|
||||
).
|
||||
WHERE(UserImagesToProcess.ID.EQ(UUID(imageId)))
|
||||
|
||||
images := []UserProcessingImage{}
|
||||
err := getToProcessStmt.QueryContext(ctx, m.dbPool, &images)
|
||||
|
||||
if len(images) != 1 {
|
||||
return UserProcessingImage{}, fmt.Errorf("Expected 1, got %d\n", len(images))
|
||||
}
|
||||
|
||||
return images[0], err
|
||||
}
|
||||
|
||||
func (m ImageModel) GetToProcessWithData(ctx context.Context, imageId uuid.UUID) (ProcessingImageData, error) {
|
||||
stmt := SELECT(UserImagesToProcess.AllColumns, Image.AllColumns).
|
||||
FROM(
|
||||
UserImagesToProcess.INNER_JOIN(
|
||||
Image, Image.ID.EQ(UserImagesToProcess.ImageID),
|
||||
),
|
||||
).WHERE(UserImagesToProcess.ID.EQ(UUID(imageId)))
|
||||
|
||||
images := []ProcessingImageData{}
|
||||
err := stmt.QueryContext(ctx, m.dbPool, &images)
|
||||
|
||||
if len(images) != 1 {
|
||||
return ProcessingImageData{}, fmt.Errorf("Expected 1, got %d\n", len(images))
|
||||
}
|
||||
|
||||
return images[0], err
|
||||
}
|
||||
|
||||
func (m ImageModel) FinishProcessing(ctx context.Context, imageId uuid.UUID) (model.UserImages, error) {
|
||||
imageToProcess, err := m.GetToProcess(ctx, imageId)
|
||||
if err != nil {
|
||||
return model.UserImages{}, err
|
||||
}
|
||||
|
||||
tx, err := m.dbPool.Begin()
|
||||
if err != nil {
|
||||
return model.UserImages{}, err
|
||||
}
|
||||
|
||||
insertImageStmt := UserImages.
|
||||
INSERT(UserImages.UserID, UserImages.ImageID).
|
||||
VALUES(imageToProcess.UserID, imageToProcess.ImageID).
|
||||
RETURNING(UserImages.ID, UserImages.UserID, UserImages.ImageID)
|
||||
|
||||
userImage := model.UserImages{}
|
||||
err = insertImageStmt.QueryContext(ctx, tx, &userImage)
|
||||
if err != nil {
|
||||
return model.UserImages{}, err
|
||||
}
|
||||
|
||||
// Hacky. Update the status before removing so we can get our regular triggers
|
||||
// to work.
|
||||
|
||||
updateStatusStmt := UserImagesToProcess.
|
||||
UPDATE(UserImagesToProcess.Status).
|
||||
SET(model.Progress_Complete).
|
||||
WHERE(UserImagesToProcess.ID.EQ(UUID(imageToProcess.ID)))
|
||||
|
||||
_, err = updateStatusStmt.ExecContext(ctx, tx)
|
||||
if err != nil {
|
||||
return model.UserImages{}, err
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// We cannot delete the image to process because our events rely on it.
|
||||
// This indicates our DB structure with the two tables might need some adjusting.
|
||||
// Or re-doing all together perhaps.
|
||||
// (switching to a one table (user_images) could work)
|
||||
// But for now, we can just not delete the images to process and set them to complete
|
||||
|
||||
// removeProcessingStmt := UserImagesToProcess.
|
||||
// DELETE().
|
||||
// WHERE(UserImagesToProcess.ID.EQ(UUID(imageToProcess.ID)))
|
||||
//
|
||||
// _, err = removeProcessingStmt.ExecContext(ctx, tx)
|
||||
// if err != nil {
|
||||
// return model.UserImages{}, err
|
||||
// }
|
||||
|
||||
err = tx.Commit()
|
||||
return userImage, err
|
||||
}
|
||||
|
||||
func (m ImageModel) GetImageToProcessID(ctx context.Context, imageID uuid.UUID) (uuid.UUID, error) {
|
||||
getImageToProcessIDStmt := UserImagesToProcess.
|
||||
SELECT(UserImagesToProcess.ID).
|
||||
WHERE(UserImagesToProcess.ImageID.EQ(UUID(imageID)))
|
||||
|
||||
imageToProcess := model.UserImagesToProcess{}
|
||||
err := getImageToProcessIDStmt.QueryContext(ctx, m.dbPool, &imageToProcess)
|
||||
|
||||
return imageToProcess.ID, err
|
||||
}
|
||||
|
||||
func (m ImageModel) SetNotStarted(ctx context.Context, processingImageId uuid.UUID) error {
|
||||
startProcessingStmt := UserImagesToProcess.
|
||||
UPDATE(UserImagesToProcess.Status).
|
||||
SET(model.Progress_NotStarted).
|
||||
WHERE(UserImagesToProcess.ID.EQ(UUID(processingImageId)))
|
||||
|
||||
_, err := startProcessingStmt.ExecContext(ctx, m.dbPool)
|
||||
_, err := saveImageStmt.ExecContext(ctx, m.dbPool)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (m ImageModel) StartProcessing(ctx context.Context, processingImageId uuid.UUID) error {
|
||||
startProcessingStmt := UserImagesToProcess.
|
||||
UPDATE(UserImagesToProcess.Status).
|
||||
SET(model.Progress_InProgress).
|
||||
WHERE(UserImagesToProcess.ID.EQ(UUID(processingImageId)))
|
||||
|
||||
_, err := startProcessingStmt.ExecContext(ctx, m.dbPool)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (m ImageModel) Get(ctx context.Context, imageId uuid.UUID) (model.Image, error) {
|
||||
getImageStmt := Image.SELECT(Image.AllColumns).
|
||||
WHERE(Image.ID.EQ(UUID(imageId)))
|
||||
func (m ImageModel) Get(ctx context.Context, imageID uuid.UUID) (model.Image, bool, error) {
|
||||
getImageStmt := Image.SELECT(Image.AllColumns.Except(Image.Image)).WHERE(Image.ID.EQ(UUID(imageID)))
|
||||
|
||||
image := model.Image{}
|
||||
err := getImageStmt.QueryContext(ctx, m.dbPool, &image)
|
||||
|
||||
return image, err
|
||||
return image, err != qrm.ErrNoRows, err
|
||||
}
|
||||
|
||||
func (m ImageModel) GetProcessing(ctx context.Context, userId uuid.UUID) ([]UserProcessingImage, error) {
|
||||
getProcessingStmt := SELECT(UserImagesToProcess.AllColumns, Image.ID, Image.ImageName).
|
||||
FROM(
|
||||
UserImagesToProcess.INNER_JOIN(
|
||||
Image, Image.ID.EQ(UserImagesToProcess.ImageID),
|
||||
),
|
||||
).WHERE(
|
||||
UserImagesToProcess.UserID.EQ(UUID(userId)).
|
||||
AND(UserImagesToProcess.Status.NOT_EQ(enum.Progress.Complete)),
|
||||
)
|
||||
func (m ImageModel) Update(ctx context.Context, image model.Image) (model.Image, error) {
|
||||
updateImageStmt := Image.UPDATE(Image.MutableColumns.Except(Image.Image)).
|
||||
MODEL(image).
|
||||
WHERE(Image.ID.EQ(UUID(image.ID))).
|
||||
RETURNING(Image.AllColumns.Except(Image.Image))
|
||||
|
||||
images := []UserProcessingImage{}
|
||||
err := getProcessingStmt.QueryContext(ctx, m.dbPool, &images)
|
||||
updatedImage := model.Image{}
|
||||
err := updateImageStmt.QueryContext(ctx, m.dbPool, &updatedImage)
|
||||
|
||||
return images, err
|
||||
return updatedImage, err
|
||||
}
|
||||
|
||||
func (m ImageModel) AddDescription(ctx context.Context, imageId uuid.UUID, description string) error {
|
||||
updateImageStmt := Image.UPDATE(Image.Description).
|
||||
SET(description).
|
||||
WHERE(Image.ID.EQ(UUID(imageId)))
|
||||
func (m ImageModel) Delete(ctx context.Context, imageID, userID uuid.UUID) (bool, error) {
|
||||
deleteImageStmt := Image.DELETE().WHERE(Image.ID.EQ(UUID(imageID)).AND(Image.UserID.EQ(UUID(userID))))
|
||||
|
||||
_, err := updateImageStmt.ExecContext(ctx, m.dbPool)
|
||||
r, err := deleteImageStmt.ExecContext(ctx, m.dbPool)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("deleting image: %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
rowsAffected, err := r.RowsAffected()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("unreachable: %w", err)
|
||||
}
|
||||
|
||||
func (m ImageModel) DeleteUserImage(ctx context.Context, imageID uuid.UUID) error {
|
||||
deleteImageStmt := UserImages.DELETE().
|
||||
WHERE(UserImages.ImageID.EQ(UUID(imageID)))
|
||||
|
||||
_, err := deleteImageStmt.ExecContext(ctx, m.dbPool)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (m ImageModel) Delete(ctx context.Context, imageID uuid.UUID) error {
|
||||
deleteImageStmt := Image.DELETE().
|
||||
WHERE(Image.ID.EQ(UUID(imageID)))
|
||||
|
||||
_, err := deleteImageStmt.ExecContext(ctx, m.dbPool)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (m ImageModel) IsUserAuthorized(ctx context.Context, imageId uuid.UUID, userId uuid.UUID) bool {
|
||||
getImageUserId := UserImages.SELECT(UserImages.UserID).WHERE(UserImages.ImageID.EQ(UUID(imageId)))
|
||||
getProcessingImageUserId := UserImagesToProcess.SELECT(UserImagesToProcess.UserID).WHERE(UserImagesToProcess.ImageID.EQ(UUID(imageId)))
|
||||
|
||||
userImage := model.UserImages{}
|
||||
userProcessingImage := model.UserImagesToProcess{}
|
||||
|
||||
err1 := getImageUserId.QueryContext(ctx, m.dbPool, &userImage)
|
||||
err2 := getProcessingImageUserId.QueryContext(ctx, m.dbPool, &userProcessingImage)
|
||||
|
||||
return (err1 == nil || err1 == qrm.ErrNoRows) && (err2 == nil || err2 == qrm.ErrNoRows) && (userImage.UserID.String() == userId.String() || userProcessingImage.UserID.String() == userId.String())
|
||||
return rowsAffected > 0, nil
|
||||
}
|
||||
|
||||
func NewImageModel(db *sql.DB) ImageModel {
|
||||
|
@ -3,7 +3,6 @@ package models
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||
. "screenmark/screenmark/.gen/haystack/haystack/table"
|
||||
|
||||
@ -12,22 +11,18 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ListModel struct {
|
||||
type StackModel struct {
|
||||
dbPool *sql.DB
|
||||
}
|
||||
|
||||
type ListWithItems struct {
|
||||
model.Lists
|
||||
type StackWithItems struct {
|
||||
model.Stacks
|
||||
|
||||
Schema struct {
|
||||
model.Schemas
|
||||
|
||||
SchemaItems []model.SchemaItems
|
||||
}
|
||||
SchemaItems []model.SchemaItems
|
||||
}
|
||||
|
||||
type ImageWithSchema struct {
|
||||
model.ImageLists
|
||||
model.ImageStacks
|
||||
|
||||
Items []model.ImageSchemaItems
|
||||
}
|
||||
@ -41,35 +36,33 @@ type IDValue struct {
|
||||
// SELECT for lists
|
||||
// ========================================
|
||||
|
||||
func (m ListModel) List(ctx context.Context, userId uuid.UUID) ([]ListWithItems, error) {
|
||||
getListsWithItems := SELECT(
|
||||
Lists.AllColumns,
|
||||
Schemas.AllColumns,
|
||||
func (m StackModel) List(ctx context.Context, userId uuid.UUID) ([]StackWithItems, error) {
|
||||
getStacksWithItems := SELECT(
|
||||
Stacks.AllColumns,
|
||||
SchemaItems.AllColumns,
|
||||
).
|
||||
FROM(
|
||||
Lists.
|
||||
INNER_JOIN(Schemas, Schemas.ListID.EQ(Lists.ID)).
|
||||
INNER_JOIN(SchemaItems, SchemaItems.SchemaID.EQ(Schemas.ID)),
|
||||
Stacks.
|
||||
INNER_JOIN(SchemaItems, SchemaItems.StackID.EQ(Stacks.ID)),
|
||||
).
|
||||
WHERE(Lists.UserID.EQ(UUID(userId)))
|
||||
WHERE(Stacks.UserID.EQ(UUID(userId)))
|
||||
|
||||
lists := []ListWithItems{}
|
||||
err := getListsWithItems.QueryContext(ctx, m.dbPool, &lists)
|
||||
lists := []StackWithItems{}
|
||||
err := getStacksWithItems.QueryContext(ctx, m.dbPool, &lists)
|
||||
|
||||
return lists, err
|
||||
}
|
||||
|
||||
func (m ListModel) ListItems(ctx context.Context, listID uuid.UUID) ([]ImageWithSchema, error) {
|
||||
func (m StackModel) ListItems(ctx context.Context, listID uuid.UUID) ([]ImageWithSchema, error) {
|
||||
getListItems := SELECT(
|
||||
ImageLists.AllColumns,
|
||||
ImageStacks.AllColumns,
|
||||
ImageSchemaItems.AllColumns,
|
||||
).
|
||||
FROM(
|
||||
ImageLists.
|
||||
INNER_JOIN(ImageSchemaItems, ImageSchemaItems.ImageID.EQ(ImageLists.ImageID)),
|
||||
ImageStacks.
|
||||
INNER_JOIN(ImageSchemaItems, ImageSchemaItems.ImageID.EQ(ImageStacks.ImageID)),
|
||||
).
|
||||
WHERE(ImageLists.ListID.EQ(UUID(listID)))
|
||||
WHERE(ImageStacks.StackID.EQ(UUID(listID)))
|
||||
|
||||
listItems := make([]ImageWithSchema, 0)
|
||||
err := getListItems.QueryContext(ctx, m.dbPool, &listItems)
|
||||
@ -77,174 +70,45 @@ func (m ListModel) ListItems(ctx context.Context, listID uuid.UUID) ([]ImageWith
|
||||
return listItems, err
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// SELECT for specific items
|
||||
// ========================================
|
||||
func (m StackModel) Get(ctx context.Context, listID uuid.UUID) (model.Stacks, error) {
|
||||
getStackStmt := Stacks.SELECT(Stacks.AllColumns).WHERE(Stacks.ID.EQ(UUID(listID)))
|
||||
|
||||
func (m ListModel) GetProcessing(ctx context.Context, processingListID uuid.UUID) (model.ProcessingLists, error) {
|
||||
getProcessingListStmt := ProcessingLists.
|
||||
SELECT(ProcessingLists.AllColumns).
|
||||
WHERE(ProcessingLists.ID.EQ(UUID(processingListID)))
|
||||
stack := model.Stacks{}
|
||||
err := getStackStmt.QueryContext(ctx, m.dbPool, &stack)
|
||||
|
||||
list := model.ProcessingLists{}
|
||||
err := getProcessingListStmt.QueryContext(ctx, m.dbPool, &list)
|
||||
|
||||
return list, err
|
||||
}
|
||||
|
||||
func (m ListModel) GetToProcess(ctx context.Context, listID uuid.UUID) (model.ProcessingLists, error) {
|
||||
getToProcessStmt := ProcessingLists.
|
||||
SELECT(ProcessingLists.AllColumns).
|
||||
WHERE(ProcessingLists.ID.EQ(UUID(listID)))
|
||||
|
||||
stack := []model.ProcessingLists{}
|
||||
err := getToProcessStmt.QueryContext(ctx, m.dbPool, &stack)
|
||||
|
||||
if len(stack) != 1 {
|
||||
return model.ProcessingLists{}, fmt.Errorf("Expected 1, got %d\n", len(stack))
|
||||
}
|
||||
|
||||
return stack[0], err
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// UPDATE
|
||||
// ========================================
|
||||
|
||||
func (m ListModel) StartProcessing(ctx context.Context, processingListID uuid.UUID) error {
|
||||
startProcessingStmt := ProcessingLists.
|
||||
UPDATE(ProcessingLists.Status).
|
||||
SET(model.Progress_InProgress).
|
||||
WHERE(ProcessingLists.ID.EQ(UUID(processingListID)))
|
||||
|
||||
_, err := startProcessingStmt.ExecContext(ctx, m.dbPool)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m ListModel) EndProcessing(ctx context.Context, processingListID uuid.UUID) error {
|
||||
startProcessingStmt := ProcessingLists.
|
||||
UPDATE(ProcessingLists.Status).
|
||||
SET(model.Progress_Complete).
|
||||
WHERE(ProcessingLists.ID.EQ(UUID(processingListID)))
|
||||
|
||||
_, err := startProcessingStmt.ExecContext(ctx, m.dbPool)
|
||||
return err
|
||||
return stack, err
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// INSERT methods
|
||||
// ========================================
|
||||
|
||||
func (m ListModel) Save(ctx context.Context, userId uuid.UUID, name string, description string, schemaItems []model.SchemaItems) (ListWithItems, error) {
|
||||
tx, err := m.dbPool.BeginTx(ctx, nil)
|
||||
func (m StackModel) Save(ctx context.Context, userID uuid.UUID, name string, description string) (model.Stacks, error) {
|
||||
saveListStmt := Stacks.
|
||||
INSERT(Stacks.UserID, Stacks.Name, Stacks.Description).
|
||||
VALUES(userID, name, description).
|
||||
RETURNING(Stacks.ID, Stacks.UserID, Stacks.Name, Stacks.Description, Stacks.CreatedAt)
|
||||
|
||||
stmt := Lists.INSERT(Lists.UserID, Lists.Name, Lists.Description).
|
||||
VALUES(userId, name, description).
|
||||
RETURNING(Lists.ID, Lists.Name, Lists.Description)
|
||||
list := model.Stacks{}
|
||||
err := saveListStmt.QueryContext(ctx, m.dbPool, &list)
|
||||
|
||||
newList := model.Lists{}
|
||||
err = stmt.QueryContext(ctx, tx, &newList)
|
||||
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return ListWithItems{}, fmt.Errorf("Could not save new list. %s", err)
|
||||
}
|
||||
|
||||
insertSchemaStmt := Schemas.INSERT(Schemas.ListID).
|
||||
VALUES(newList.ID).
|
||||
RETURNING(Schemas.ID)
|
||||
|
||||
newSchema := model.Schemas{}
|
||||
err = insertSchemaStmt.QueryContext(ctx, tx, &newSchema)
|
||||
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return ListWithItems{}, fmt.Errorf("Could not save new schema. %s", err)
|
||||
}
|
||||
|
||||
// This is very interesting...
|
||||
for i := range schemaItems {
|
||||
schemaItems[i].SchemaID = newSchema.ID
|
||||
}
|
||||
|
||||
insertSchemaItemsStmt := SchemaItems.INSERT(SchemaItems.Item, SchemaItems.Value, SchemaItems.Description, SchemaItems.SchemaID).
|
||||
MODELS(schemaItems)
|
||||
_, err = insertSchemaItemsStmt.ExecContext(ctx, tx)
|
||||
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return ListWithItems{}, fmt.Errorf("Could not save schema items. %s", err)
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return ListWithItems{}, fmt.Errorf("Could not commit transaction. %s", err)
|
||||
}
|
||||
|
||||
getListAndItems := SELECT(Lists.AllColumns, Schemas.AllColumns, SchemaItems.AllColumns).
|
||||
FROM(
|
||||
Lists.
|
||||
INNER_JOIN(Schemas, Schemas.ListID.EQ(Lists.ID)).
|
||||
INNER_JOIN(SchemaItems, SchemaItems.SchemaID.EQ(Schemas.ID)),
|
||||
).
|
||||
WHERE(Lists.ID.EQ(UUID(newList.ID)))
|
||||
|
||||
listWithItems := ListWithItems{}
|
||||
err = getListAndItems.QueryContext(ctx, m.dbPool, &listWithItems)
|
||||
|
||||
return listWithItems, err
|
||||
return list, err
|
||||
}
|
||||
|
||||
func (m ListModel) SaveInto(ctx context.Context, listID uuid.UUID, imageID uuid.UUID, schemaValues []IDValue) error {
|
||||
tx, err := m.dbPool.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (m StackModel) SaveItems(ctx context.Context, items []model.SchemaItems) error {
|
||||
saveItemsStmt := SchemaItems.INSERT(SchemaItems.AllColumns).MODELS(items)
|
||||
|
||||
var imageList model.ImageLists
|
||||
stmt := ImageLists.INSERT(ImageLists.ListID, ImageLists.ImageID).
|
||||
VALUES(listID, imageID).
|
||||
RETURNING(ImageLists.ID)
|
||||
_, err := saveItemsStmt.ExecContext(ctx, m.dbPool)
|
||||
|
||||
err = stmt.QueryContext(ctx, m.dbPool, &imageList)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return fmt.Errorf("Could not insert new list. %s", err)
|
||||
}
|
||||
|
||||
imageSchemaItems := make([]model.ImageSchemaItems, len(schemaValues))
|
||||
|
||||
for i, v := range schemaValues {
|
||||
parsedId, err := uuid.Parse(v.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
imageSchemaItems[i].SchemaItemID = parsedId
|
||||
imageSchemaItems[i].ImageID = imageList.ID
|
||||
imageSchemaItems[i].Value = &v.Value
|
||||
}
|
||||
|
||||
insertSchemaItemsStmt := ImageSchemaItems.
|
||||
INSERT(ImageSchemaItems.Value, ImageSchemaItems.SchemaItemID, ImageSchemaItems.ImageID).
|
||||
MODELS(imageSchemaItems)
|
||||
|
||||
_, err = insertSchemaItemsStmt.ExecContext(ctx, tx)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return fmt.Errorf("Could not insert schema items. %s", err)
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
return err
|
||||
}
|
||||
|
||||
func (m ListModel) SaveProcessing(ctx context.Context, userID uuid.UUID, title string, fields string) error {
|
||||
insertListToProcess := ProcessingLists.
|
||||
INSERT(ProcessingLists.UserID, ProcessingLists.Title, ProcessingLists.Fields).
|
||||
VALUES(userID, title, fields)
|
||||
func (m StackModel) SaveImage(ctx context.Context, imageID uuid.UUID, stackID uuid.UUID) error {
|
||||
saveImageStmt := ImageStacks.
|
||||
INSERT(ImageStacks.ImageID, ImageStacks.StackID).
|
||||
VALUES(imageID, stackID)
|
||||
|
||||
_, err := insertListToProcess.ExecContext(ctx, m.dbPool)
|
||||
_, err := saveImageStmt.ExecContext(ctx, m.dbPool)
|
||||
|
||||
return err
|
||||
}
|
||||
@ -253,11 +117,11 @@ func (m ListModel) SaveProcessing(ctx context.Context, userID uuid.UUID, title s
|
||||
// DELETE methods
|
||||
// ========================================
|
||||
|
||||
func (m ListModel) DeleteImage(ctx context.Context, listID uuid.UUID, imageID uuid.UUID) error {
|
||||
deleteImageListStmt := ImageLists.DELETE().
|
||||
func (m StackModel) DeleteImage(ctx context.Context, listID uuid.UUID, imageID uuid.UUID) error {
|
||||
deleteImageListStmt := ImageStacks.DELETE().
|
||||
WHERE(
|
||||
ImageLists.ListID.EQ(UUID(listID)).
|
||||
AND(ImageLists.ImageID.EQ(UUID(imageID))),
|
||||
ImageStacks.StackID.EQ(UUID(listID)).
|
||||
AND(ImageStacks.ImageID.EQ(UUID(imageID))),
|
||||
)
|
||||
|
||||
_, err := deleteImageListStmt.ExecContext(ctx, m.dbPool)
|
||||
@ -265,60 +129,14 @@ func (m ListModel) DeleteImage(ctx context.Context, listID uuid.UUID, imageID uu
|
||||
return err
|
||||
}
|
||||
|
||||
func (m ListModel) Delete(ctx context.Context, listID uuid.UUID, userID uuid.UUID) error {
|
||||
// First verify the list belongs to the user
|
||||
checkOwnershipStmt := Lists.
|
||||
SELECT(Lists.ID).
|
||||
WHERE(Lists.ID.EQ(UUID(listID)).AND(Lists.UserID.EQ(UUID(userID))))
|
||||
func (m StackModel) Delete(ctx context.Context, listID uuid.UUID, userID uuid.UUID) error {
|
||||
deleteStackStmt := Stacks.DELETE().WHERE(Stacks.ID.EQ(UUID(listID)).AND(Stacks.UserID.EQ(UUID(userID))))
|
||||
|
||||
var existingList model.Lists
|
||||
err := checkOwnershipStmt.QueryContext(ctx, m.dbPool, &existingList)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not verify list ownership: %w", err)
|
||||
}
|
||||
_, err := deleteStackStmt.ExecContext(ctx, m.dbPool)
|
||||
|
||||
// Start a transaction to ensure all deletions happen atomically
|
||||
tx, err := m.dbPool.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not start transaction: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
// Delete in reverse order of dependencies:
|
||||
// 1. Delete schema items first
|
||||
deleteSchemaItemsStmt := SchemaItems.DELETE().
|
||||
WHERE(SchemaItems.SchemaID.IN(
|
||||
Schemas.SELECT(Schemas.ID).
|
||||
WHERE(Schemas.ListID.EQ(UUID(listID))),
|
||||
))
|
||||
_, err = deleteSchemaItemsStmt.ExecContext(ctx, tx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not delete schema items: %w", err)
|
||||
}
|
||||
|
||||
// 2. Delete schemas
|
||||
deleteSchemasStmt := Schemas.DELETE().WHERE(Schemas.ListID.EQ(UUID(listID)))
|
||||
_, err = deleteSchemasStmt.ExecContext(ctx, tx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not delete schemas: %w", err)
|
||||
}
|
||||
|
||||
// 3. Delete the list itself
|
||||
deleteListStmt := Lists.DELETE().WHERE(Lists.ID.EQ(UUID(listID)))
|
||||
_, err = deleteListStmt.ExecContext(ctx, tx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not delete list: %w", err)
|
||||
}
|
||||
|
||||
// Commit the transaction
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not commit transaction: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func NewListModel(db *sql.DB) ListModel {
|
||||
return ListModel{dbPool: db}
|
||||
func NewListModel(db *sql.DB) StackModel {
|
||||
return StackModel{dbPool: db}
|
||||
}
|
||||
|
@ -49,28 +49,20 @@ func (m UserModel) Save(ctx context.Context, user model.Users) (model.Users, err
|
||||
}
|
||||
|
||||
type UserImageWithImage struct {
|
||||
model.UserImages
|
||||
|
||||
Image struct {
|
||||
model.Image
|
||||
ImageLists []model.ImageLists
|
||||
}
|
||||
model.Image
|
||||
ImageStacks []model.ImageStacks
|
||||
}
|
||||
|
||||
func (m UserModel) GetUserImages(ctx context.Context, userId uuid.UUID) ([]UserImageWithImage, error) {
|
||||
getUserImagesStmt := SELECT(
|
||||
UserImages.AllColumns,
|
||||
Image.ID,
|
||||
Image.ImageName,
|
||||
Image.Description,
|
||||
ImageLists.AllColumns,
|
||||
Image.AllColumns.Except(Image.Image),
|
||||
ImageStacks.AllColumns,
|
||||
).
|
||||
FROM(
|
||||
UserImages.
|
||||
INNER_JOIN(Image, Image.ID.EQ(UserImages.ImageID)).
|
||||
LEFT_JOIN(ImageLists, ImageLists.ImageID.EQ(UserImages.ImageID)),
|
||||
Image.
|
||||
LEFT_JOIN(ImageStacks, ImageStacks.ImageID.EQ(ImageStacks.ID)),
|
||||
).
|
||||
WHERE(UserImages.UserID.EQ(UUID(userId)))
|
||||
WHERE(Image.UserID.EQ(UUID(userId)))
|
||||
|
||||
userImages := []UserImageWithImage{}
|
||||
err := getUserImagesStmt.QueryContext(ctx, m.dbPool, &userImages)
|
||||
@ -79,16 +71,12 @@ func (m UserModel) GetUserImages(ctx context.Context, userId uuid.UUID) ([]UserI
|
||||
}
|
||||
|
||||
type ListsWithImages struct {
|
||||
model.Lists
|
||||
model.Stacks
|
||||
|
||||
Schema struct {
|
||||
model.Schemas
|
||||
|
||||
SchemaItems []model.SchemaItems
|
||||
}
|
||||
SchemaItems []model.SchemaItems
|
||||
|
||||
Images []struct {
|
||||
model.ImageLists
|
||||
model.ImageStacks
|
||||
|
||||
Items []model.ImageSchemaItems
|
||||
}
|
||||
@ -96,20 +84,18 @@ type ListsWithImages struct {
|
||||
|
||||
func (m UserModel) ListWithImages(ctx context.Context, userId uuid.UUID) ([]ListsWithImages, error) {
|
||||
stmt := SELECT(
|
||||
Lists.AllColumns,
|
||||
ImageLists.AllColumns,
|
||||
Schemas.AllColumns,
|
||||
Stacks.AllColumns,
|
||||
ImageStacks.AllColumns,
|
||||
SchemaItems.AllColumns,
|
||||
ImageSchemaItems.AllColumns,
|
||||
).
|
||||
FROM(
|
||||
Lists.
|
||||
INNER_JOIN(Schemas, Schemas.ListID.EQ(Lists.ID)).
|
||||
INNER_JOIN(SchemaItems, SchemaItems.SchemaID.EQ(Schemas.ID)).
|
||||
LEFT_JOIN(ImageLists, ImageLists.ListID.EQ(Lists.ID)).
|
||||
LEFT_JOIN(ImageSchemaItems, ImageSchemaItems.ImageID.EQ(ImageLists.ID)),
|
||||
Stacks.
|
||||
INNER_JOIN(SchemaItems, SchemaItems.StackID.EQ(Stacks.ID)).
|
||||
LEFT_JOIN(ImageStacks, ImageStacks.StackID.EQ(Stacks.ID)).
|
||||
LEFT_JOIN(ImageSchemaItems, ImageSchemaItems.ImageID.EQ(ImageStacks.ID)),
|
||||
).
|
||||
WHERE(Lists.UserID.EQ(UUID(userId)))
|
||||
WHERE(Stacks.UserID.EQ(UUID(userId)))
|
||||
|
||||
lists := []ListsWithImages{}
|
||||
err := stmt.QueryContext(ctx, m.dbPool, &lists)
|
||||
|
95
backend/processor/image.go
Normal file
95
backend/processor/image.go
Normal file
@ -0,0 +1,95 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||
"screenmark/screenmark/agents"
|
||||
"screenmark/screenmark/agents/client"
|
||||
"screenmark/screenmark/models"
|
||||
"sync"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
)
|
||||
|
||||
const IMAGE_PROCESS_AT_A_TIME = 10
|
||||
|
||||
type ImageProcessor struct {
|
||||
imageModel models.ImageModel
|
||||
logger *log.Logger
|
||||
|
||||
descriptionAgent agents.DescriptionAgent
|
||||
listAgent client.AgentClient
|
||||
|
||||
// TODO: add the notifier here
|
||||
|
||||
processor *Processor[model.Image]
|
||||
}
|
||||
|
||||
func (p *ImageProcessor) setImageToProcess(ctx context.Context, image model.Image) {
|
||||
updatedImage := model.Image{
|
||||
ID: image.ID,
|
||||
Status: model.Progress_InProgress,
|
||||
}
|
||||
|
||||
_, err := p.imageModel.Update(ctx, updatedImage)
|
||||
if err != nil {
|
||||
// TODO: what can we actually do here for the errors?
|
||||
// We can't stop the work for the others
|
||||
|
||||
p.logger.Error("failed to update image", "err", err)
|
||||
|
||||
// TODO: we can use context here to actually pass some information through
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ImageProcessor) describe(ctx context.Context, image model.Image) {
|
||||
descriptionSubLogger := p.logger.With("describe image", image.ID)
|
||||
|
||||
err := p.descriptionAgent.Describe(descriptionSubLogger, image.ID, image.ImageName, image.Image)
|
||||
if err != nil {
|
||||
// Again, wtf do we do?
|
||||
// Although i think the agent actually returns an error when it's finished
|
||||
p.logger.Error("failed to describe image", "err", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ImageProcessor) extractInfo(ctx context.Context, image model.Image) {
|
||||
err := p.listAgent.RunAgent(*image.UserID, image.ID, image.ImageName, image.Image)
|
||||
if err != nil {
|
||||
// Again, wtf do we do?
|
||||
// Although i think the agent actually returns an error when it's finished
|
||||
p.logger.Error("failed to process image", "err", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ImageProcessor) processImage(image model.Image) {
|
||||
ctx := context.Background()
|
||||
|
||||
p.setImageToProcess(ctx, image)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
p.describe(ctx, image)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
p.extractInfo(ctx, image)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func CreateImageProcessor(logger *log.Logger, imageModel models.ImageModel) ImageProcessor {
|
||||
imageProcessor := ImageProcessor{imageModel: imageModel, logger: logger}
|
||||
|
||||
imageProcessor.processor = NewProcessor(int(IMAGE_PROCESS_AT_A_TIME), imageProcessor.processImage)
|
||||
|
||||
return imageProcessor
|
||||
}
|
19
backend/processor/processor.go
Normal file
19
backend/processor/processor.go
Normal file
@ -0,0 +1,19 @@
|
||||
package processor
|
||||
|
||||
type Processor[TMessage any] struct {
|
||||
queue chan TMessage
|
||||
process func(message TMessage)
|
||||
}
|
||||
|
||||
func (p *Processor[TMessage]) Work() {
|
||||
for msg := range p.queue {
|
||||
p.process(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func NewProcessor[TMessage any](bufferSize int, process func(message TMessage)) *Processor[TMessage] {
|
||||
return &Processor[TMessage]{
|
||||
queue: make(chan TMessage, bufferSize),
|
||||
process: process,
|
||||
}
|
||||
}
|
@ -2,12 +2,10 @@ package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"os"
|
||||
"screenmark/screenmark/agents/client"
|
||||
"screenmark/screenmark/auth"
|
||||
"screenmark/screenmark/images"
|
||||
"screenmark/screenmark/limits"
|
||||
"screenmark/screenmark/models"
|
||||
"screenmark/screenmark/stacks"
|
||||
|
||||
ourmiddleware "screenmark/screenmark/middleware"
|
||||
@ -25,33 +23,14 @@ func (client TestAiClient) GetImageInfo(imageName string, imageData []byte) (cli
|
||||
}
|
||||
|
||||
func setupRouter(db *sql.DB, jwtManager *ourmiddleware.JwtManager) chi.Router {
|
||||
imageModel := models.NewImageModel(db)
|
||||
stackModel := models.NewListModel(db)
|
||||
|
||||
limitsManager := limits.CreateLimitsManager(db)
|
||||
|
||||
processImageLogger := createLogger("Process Image", os.Stdout)
|
||||
processImage := ProcessImage(processImageLogger, db)
|
||||
|
||||
stackHandler := stacks.CreateStackHandler(db, limitsManager, jwtManager)
|
||||
authHandler := auth.CreateAuthHandler(db, jwtManager)
|
||||
imageHandler := images.CreateImageHandler(db, limitsManager, processImage, jwtManager)
|
||||
imageHandler := images.CreateImageHandler(db, limitsManager, jwtManager)
|
||||
|
||||
notifier := NewNotifier[Notification](10)
|
||||
|
||||
// Only start event listeners if not in test environment
|
||||
if os.Getenv("GO_TEST_ENVIRONMENT") != "true" {
|
||||
|
||||
// TODO: should extract these into a notification manager
|
||||
// And actually make them the same code.
|
||||
// The events are basically the same.
|
||||
|
||||
go ListenNewImageEvents(db)
|
||||
go ListenProcessingImageStatus(db, imageModel, ¬ifier)
|
||||
go ListenNewStackEvents(db)
|
||||
go ListenProcessingStackStatus(db, stackModel, ¬ifier)
|
||||
}
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Use(middleware.Logger)
|
||||
@ -67,11 +46,5 @@ func setupRouter(db *sql.DB, jwtManager *ourmiddleware.JwtManager) chi.Router {
|
||||
r.Get("/", CreateEventsHandler(¬ifier))
|
||||
})
|
||||
|
||||
logWriter := DatabaseWriter{
|
||||
dbPool: db,
|
||||
}
|
||||
|
||||
r.Route("/logs", createLogHandler(&logWriter))
|
||||
|
||||
return r
|
||||
}
|
||||
|
@ -9,72 +9,43 @@ CREATE TYPE haystack.progress AS ENUM('not-started','in-progress', 'complete');
|
||||
/* -----| Schema tables |----- */
|
||||
|
||||
CREATE TABLE haystack.users (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
email TEXT NOT NULL
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
email TEXT NOT NULL,
|
||||
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE haystack.image (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID REFERENCES haystack.users (id),
|
||||
|
||||
image_name TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
image BYTEA NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE haystack.user_images_to_process (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
status haystack.progress NOT NULL DEFAULT 'not-started',
|
||||
image_id uuid NOT NULL UNIQUE REFERENCES haystack.image (id) ON DELETE CASCADE,
|
||||
user_id uuid NOT NULL REFERENCES haystack.users (id)
|
||||
);
|
||||
|
||||
CREATE TABLE haystack.user_images (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
image_id uuid NOT NULL UNIQUE REFERENCES haystack.image (id) ON DELETE CASCADE,
|
||||
user_id uuid NOT NULL REFERENCES haystack.users (id),
|
||||
image BYTEA NOT NULL,
|
||||
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE haystack.logs (
|
||||
log TEXT NOT NULL,
|
||||
image_id UUID NOT NULL REFERENCES haystack.image (id) ON DELETE CASCADE,
|
||||
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE haystack.lists (
|
||||
CREATE TABLE haystack.stacks (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES haystack.users (id),
|
||||
|
||||
status haystack.progress NOT NULL DEFAULT 'not-started',
|
||||
|
||||
name TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE haystack.processing_lists (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES haystack.users (id),
|
||||
|
||||
title TEXT NOT NULL,
|
||||
fields TEXT NOT NULL,
|
||||
|
||||
status haystack.progress NOT NULL DEFAULT 'not-started',
|
||||
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE haystack.image_lists (
|
||||
CREATE TABLE haystack.image_stacks (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
||||
image_id UUID NOT NULL REFERENCES haystack.image (id) ON DELETE CASCADE,
|
||||
list_id UUID NOT NULL REFERENCES haystack.lists (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE haystack.schemas (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
||||
list_id UUID NOT NULL REFERENCES haystack.lists (id) ON DELETE CASCADE
|
||||
stack_id UUID NOT NULL REFERENCES haystack.stacks (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE haystack.schema_items (
|
||||
@ -84,7 +55,7 @@ CREATE TABLE haystack.schema_items (
|
||||
value TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
|
||||
schema_id UUID NOT NULL REFERENCES haystack.schemas (id)
|
||||
stack_id UUID NOT NULL REFERENCES haystack.stacks (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE haystack.image_schema_items (
|
||||
@ -92,68 +63,6 @@ CREATE TABLE haystack.image_schema_items (
|
||||
|
||||
value TEXT,
|
||||
|
||||
schema_item_id UUID NOT NULL REFERENCES haystack.schema_items (id),
|
||||
image_id UUID NOT NULL REFERENCES haystack.image_lists (id) ON DELETE CASCADE
|
||||
schema_item_id UUID NOT NULL REFERENCES haystack.schema_items (id) ON DELETE CASCADE,
|
||||
image_id UUID NOT NULL REFERENCES haystack.image_stacks (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
/* -----| Indexes |----- */
|
||||
|
||||
/* -----| Stored Procedures |----- */
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_new_image()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
PERFORM pg_notify('new_image', NEW.id::texT);
|
||||
RETURN NEW;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_new_processing_image_status()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF NEW.status <> 'not-started' THEN
|
||||
PERFORM pg_notify('new_processing_image_status', NEW.id::text || NEW.status::text);
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_new_stacks()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
PERFORM pg_notify('new_stack', NEW.id::text);
|
||||
RETURN NEW;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_new_processing_stack_status()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
PERFORM pg_notify('new_processing_stack_status', NEW.id::text || NEW.status::text);
|
||||
RETURN NEW;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
/* -----| Triggers |----- */
|
||||
|
||||
CREATE OR REPLACE TRIGGER on_new_image AFTER INSERT
|
||||
ON haystack.user_images_to_process
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE notify_new_image();
|
||||
|
||||
CREATE OR REPLACE TRIGGER on_update_image_progress
|
||||
AFTER UPDATE OF status
|
||||
ON haystack.user_images_to_process
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE notify_new_processing_image_status();
|
||||
|
||||
CREATE OR REPLACE TRIGGER on_new_image AFTER INSERT
|
||||
ON haystack.processing_lists
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE notify_new_stacks();
|
||||
|
||||
CREATE OR REPLACE TRIGGER on_update_stack_progress
|
||||
AFTER UPDATE OF status
|
||||
ON haystack.processing_lists
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE notify_new_processing_stack_status();
|
||||
|
@ -2,14 +2,11 @@ package stacks
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
. "screenmark/screenmark/.gen/haystack/haystack/model"
|
||||
"screenmark/screenmark/limits"
|
||||
"screenmark/screenmark/middleware"
|
||||
"screenmark/screenmark/models"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/go-chi/chi/v5"
|
||||
@ -20,7 +17,7 @@ type StackHandler struct {
|
||||
logger *log.Logger
|
||||
|
||||
imageModel models.ImageModel
|
||||
stackModel models.ListModel
|
||||
stackModel models.StackModel
|
||||
|
||||
limitsManager limits.LimitsManagerMethods
|
||||
|
||||
@ -125,8 +122,13 @@ func (h *StackHandler) deleteImageFromStack(w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
isAuthorized := h.imageModel.IsUserAuthorized(ctx, imageID, userID)
|
||||
if !isAuthorized {
|
||||
stack, err := h.stackModel.Get(ctx, listID)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if stack.UserID != userID {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
@ -142,10 +144,8 @@ func (h *StackHandler) deleteImageFromStack(w http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
|
||||
type CreateStackBody struct {
|
||||
Title string `json:"title"`
|
||||
|
||||
// We want a regular string because AI will take care of creating these for us.
|
||||
Fields string `json:"fields"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (h *StackHandler) createStack(body CreateStackBody, w http.ResponseWriter, r *http.Request) {
|
||||
@ -155,25 +155,7 @@ func (h *StackHandler) createStack(body CreateStackBody, w http.ResponseWriter,
|
||||
return
|
||||
}
|
||||
|
||||
// Convert fields string to basic schema items
|
||||
// For now, create a simple schema item for each field
|
||||
var schemaItems []SchemaItems
|
||||
if body.Fields != "" {
|
||||
fields := strings.Split(body.Fields, ",")
|
||||
for i, field := range fields {
|
||||
field = strings.TrimSpace(field)
|
||||
if field != "" {
|
||||
schemaItems = append(schemaItems, SchemaItems{
|
||||
Item: field,
|
||||
Value: "",
|
||||
Description: fmt.Sprintf("Field %d: %s", i+1, field),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use empty description for now since the API doesn't provide one
|
||||
_, err = h.stackModel.Save(ctx, userID, body.Title, "", schemaItems)
|
||||
_, err = h.stackModel.Save(ctx, userID, body.Title, body.Description)
|
||||
if err != nil {
|
||||
h.logger.Warn("could not save stack", "err", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
@ -67,7 +67,7 @@ export const ImageComponentFullHeight: Component<ImageComponentProps> = (props)
|
||||
const [accessToken] = createResource(getAccessToken);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Suspense>
|
||||
<div class="relative w-full flex justify-center">
|
||||
<A href={`/image/${props.ID}`} class="flex w-full">
|
||||
<img
|
||||
@ -107,6 +107,6 @@ export const ImageComponentFullHeight: Component<ImageComponentProps> = (props)
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
||||
</>
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
Reference in New Issue
Block a user