feat: extend problem fields
This commit is contained in:
parent
3ed195bb58
commit
6dc8f05675
14 changed files with 70 additions and 362 deletions
|
@ -1,44 +0,0 @@
|
||||||
package problem.rbac
|
|
||||||
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
spectator := 0
|
|
||||||
participant := 1
|
|
||||||
moderator := 2
|
|
||||||
admin := 3
|
|
||||||
|
|
||||||
permissions := {
|
|
||||||
"read": is_spectator,
|
|
||||||
"participate": is_participant,
|
|
||||||
"update": is_moderator,
|
|
||||||
"create": is_moderator,
|
|
||||||
"delete": is_moderator,
|
|
||||||
}
|
|
||||||
|
|
||||||
default allow := false
|
|
||||||
|
|
||||||
allow if is_admin
|
|
||||||
|
|
||||||
allow if {
|
|
||||||
permissions[input.action]
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_admin := false
|
|
||||||
is_admin if {
|
|
||||||
input.user.role == admin
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_moderator := false
|
|
||||||
is_moderator if {
|
|
||||||
input.user.role >= moderator
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_participant := false
|
|
||||||
is_participant if {
|
|
||||||
input.user.role >= participant
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_spectator := true
|
|
||||||
is_spectator if {
|
|
||||||
input.user.role >= spectator
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package usecase
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
|
||||||
"github.com/open-policy-agent/opa/rego"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PermissionService struct {
|
|
||||||
query *rego.PreparedEvalQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPermissionService() *PermissionService {
|
|
||||||
query, err := rego.New(
|
|
||||||
rego.Query("allow = data.problem.rbac.allow"),
|
|
||||||
rego.Load([]string{"./opa/problem.rego"}, nil),
|
|
||||||
).PrepareForEval(context.TODO())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &PermissionService{
|
|
||||||
query: &query,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PermissionService) Allowed(ctx context.Context, user *models.User, action string) bool {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"user": user,
|
|
||||||
"action": action,
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := s.query.Eval(ctx, rego.EvalInput(input))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return result[0].Bindings["allow"].(bool)
|
|
||||||
}
|
|
|
@ -1,8 +1,12 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
type Participant struct {
|
type Participant struct {
|
||||||
Id *int32 `db:"id"`
|
Id *int32 `db:"id"`
|
||||||
UserId *int32 `db:"user_id"`
|
UserId *int32 `db:"user_id"`
|
||||||
ContestId *int32 `db:"contest_id"`
|
ContestId *int32 `db:"contest_id"`
|
||||||
Name *string `db:"name"`
|
Name *string `db:"name"`
|
||||||
|
CreatedAt *time.Time `db:"created_at"`
|
||||||
|
UpdatedAt *time.Time `db:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,16 @@ package models
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Problem struct {
|
type Problem struct {
|
||||||
Id *int32 `db:"id"`
|
Id *int32 `db:"id"`
|
||||||
Title *string `db:"title"`
|
Title *string `db:"title"`
|
||||||
Content *string `db:"content"`
|
Legend *string `db:"legend"`
|
||||||
TimeLimit *int32 `db:"time_limit"`
|
InputFormat *string `db:"input_format"`
|
||||||
MemoryLimit *int32 `db:"memory_limit"`
|
OutputFormat *string `db:"output_format"`
|
||||||
TestingStrategy *int32 `db:"testing_strategy"`
|
Notes *string `db:"notes"`
|
||||||
TestingOrder *string `db:"testing_order"`
|
Tutorial *string `db:"tutorial"`
|
||||||
CreatedAt *time.Time `db:"created_at"`
|
LatexSummary *string `db:"latex_summary"`
|
||||||
UpdatedAt *time.Time `db:"updated_at"`
|
TimeLimit *int32 `db:"time_limit"`
|
||||||
|
MemoryLimit *int32 `db:"memory_limit"`
|
||||||
|
CreatedAt *time.Time `db:"created_at"`
|
||||||
|
UpdatedAt *time.Time `db:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@ import "time"
|
||||||
|
|
||||||
type Solution struct {
|
type Solution struct {
|
||||||
Id *int32 `db:"id"`
|
Id *int32 `db:"id"`
|
||||||
ParticipantId *int32 `db:"participant_id"`
|
|
||||||
TaskId *int32 `db:"task_id"`
|
TaskId *int32 `db:"task_id"`
|
||||||
LanguageId *int32 `db:"language_id"`
|
ParticipantId *int32 `db:"participant_id"`
|
||||||
SolutionHash *string `db:"solution_hash"`
|
State *int32 `db:"state"`
|
||||||
Result *int32 `db:"result"`
|
|
||||||
Score *int32 `db:"score"`
|
Score *int32 `db:"score"`
|
||||||
|
Penalty *int32 `db:"penalty"`
|
||||||
|
TotalScore *int32 `db:"total_score"`
|
||||||
|
Language *int32 `db:"language"`
|
||||||
CreatedAt *time.Time `db:"created_at"`
|
CreatedAt *time.Time `db:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
type Task struct {
|
type Task struct {
|
||||||
Id *int32 `db:"id"`
|
Id *int32 `db:"id"`
|
||||||
ContestId *int32 `db:"contest_id"`
|
ProblemId *int32 `db:"problem_id"`
|
||||||
ProblemId *int32 `db:"problem_id"`
|
ContestId *int32 `db:"contest_id"`
|
||||||
Position *int32 `db:"position"`
|
Position *int32 `db:"position"`
|
||||||
PositionName *string `db:"position_name"`
|
CreatedAt *time.Time `db:"created_at"`
|
||||||
|
UpdatedAt *time.Time `db:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
package models
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
UserId *int32 `json:"user_id" db:"user_id"`
|
|
||||||
Role *Role `json:"role" db:"role"`
|
|
||||||
UpdatedAt *time.Time `json:"updated_at" db:"updated_at"`
|
|
||||||
}
|
|
|
@ -36,15 +36,18 @@ func (h *problemHandlers) ReadProblem(ctx context.Context, req *problemv1.ReadPr
|
||||||
}
|
}
|
||||||
return &problemv1.ReadProblemResponse{
|
return &problemv1.ReadProblemResponse{
|
||||||
Problem: &problemv1.ReadProblemResponse_Problem{
|
Problem: &problemv1.ReadProblemResponse_Problem{
|
||||||
Id: *problem.Id,
|
Id: *problem.Id,
|
||||||
Title: *problem.Title,
|
Title: *problem.Title,
|
||||||
Content: *problem.Content,
|
Legend: *problem.Legend,
|
||||||
TimeLimit: *problem.TimeLimit,
|
InputFormat: *problem.InputFormat,
|
||||||
MemoryLimit: *problem.MemoryLimit,
|
OutputFormat: *problem.OutputFormat,
|
||||||
TestingStrategy: *problem.TestingStrategy,
|
Notes: *problem.Notes,
|
||||||
TestingOrder: *problem.TestingOrder,
|
Tutorial: *problem.Tutorial,
|
||||||
CreatedAt: utils.TimestampP(problem.CreatedAt),
|
LatexSummary: *problem.LatexSummary,
|
||||||
UpdatedAt: utils.TimestampP(problem.UpdatedAt),
|
TimeLimit: *problem.TimeLimit,
|
||||||
|
MemoryLimit: *problem.MemoryLimit,
|
||||||
|
CreatedAt: utils.TimestampP(problem.CreatedAt),
|
||||||
|
UpdatedAt: utils.TimestampP(problem.UpdatedAt),
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
package usecase
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
|
||||||
"github.com/open-policy-agent/opa/rego"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PermissionService struct {
|
|
||||||
query *rego.PreparedEvalQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPermissionService() *PermissionService {
|
|
||||||
query, err := rego.New(
|
|
||||||
rego.Query("allow = data.problem.rbac.allow"),
|
|
||||||
rego.Load([]string{"./opa/problem.rego"}, nil),
|
|
||||||
).PrepareForEval(context.TODO())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &PermissionService{
|
|
||||||
query: &query,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PermissionService) Allowed(ctx context.Context, user *models.User, action string) bool {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"user": user,
|
|
||||||
"action": action,
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := s.query.Eval(ctx, rego.EvalInput(input))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return result[0].Bindings["allow"].(bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
//func (service *ProblemUseCase) CanCreateProblem(ctx context.Context) error {
|
|
||||||
// if !service.permissionService.Allowed(ctx, extractUser(ctx), "create") {
|
|
||||||
// return utils.ServiceError(nil, utils.ErrNoPermission, "permission denied")
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (service *ProblemUseCase) CanReadProblemById(ctx context.Context) error {
|
|
||||||
// if !service.permissionService.Allowed(ctx, extractUser(ctx), "read") {
|
|
||||||
// return utils.ServiceError(nil, utils.ErrNoPermission, "permission denied")
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (service *ProblemUseCase) CanUpdateProblem(ctx context.Context) error {
|
|
||||||
// if !service.permissionService.Allowed(ctx, extractUser(ctx), "update") {
|
|
||||||
// return utils.ServiceError(nil, utils.ErrNoPermission, "permission denied")
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (service *ProblemUseCase) CanDeleteProblem(ctx context.Context) error {
|
|
||||||
// if !service.permissionService.Allowed(ctx, extractUser(ctx), "delete") {
|
|
||||||
// return utils.ServiceError(nil, utils.ErrNoPermission, "permission denied")
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
//}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package problem.rbac
|
|
||||||
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
spectator := 0
|
|
||||||
participant := 1
|
|
||||||
moderator := 2
|
|
||||||
admin := 3
|
|
||||||
|
|
||||||
permissions := {
|
|
||||||
"read": is_spectator,
|
|
||||||
"participate": is_participant,
|
|
||||||
"update": is_moderator,
|
|
||||||
"create": is_moderator,
|
|
||||||
"delete": is_moderator,
|
|
||||||
}
|
|
||||||
|
|
||||||
default allow := false
|
|
||||||
|
|
||||||
allow if is_admin
|
|
||||||
|
|
||||||
allow if {
|
|
||||||
permissions[input.action]
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_admin := false
|
|
||||||
is_admin if {
|
|
||||||
input.user.role == admin
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_moderator := false
|
|
||||||
is_moderator if {
|
|
||||||
input.user.role >= moderator
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_participant := false
|
|
||||||
is_participant if {
|
|
||||||
input.user.role >= participant
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_spectator := true
|
|
||||||
is_spectator if {
|
|
||||||
input.user.role >= spectator
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package problem.rbac
|
|
||||||
|
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
spectator := 0
|
|
||||||
participant := 1
|
|
||||||
moderator := 2
|
|
||||||
admin := 3
|
|
||||||
|
|
||||||
permissions := {
|
|
||||||
"read": is_spectator,
|
|
||||||
"participate": is_participant,
|
|
||||||
"update": is_moderator,
|
|
||||||
"create": is_moderator,
|
|
||||||
"delete": is_moderator,
|
|
||||||
}
|
|
||||||
|
|
||||||
default allow := false
|
|
||||||
|
|
||||||
allow if is_admin
|
|
||||||
|
|
||||||
allow if {
|
|
||||||
permissions[input.action]
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_admin := false
|
|
||||||
is_admin if {
|
|
||||||
input.user.role == admin
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_moderator := false
|
|
||||||
is_moderator if {
|
|
||||||
input.user.role >= moderator
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_participant := false
|
|
||||||
is_participant if {
|
|
||||||
input.user.role >= participant
|
|
||||||
}
|
|
||||||
|
|
||||||
default is_spectator := true
|
|
||||||
is_spectator if {
|
|
||||||
input.user.role >= spectator
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package usecase
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
|
||||||
"github.com/open-policy-agent/opa/rego"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PermissionService struct {
|
|
||||||
query *rego.PreparedEvalQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPermissionService() *PermissionService {
|
|
||||||
query, err := rego.New(
|
|
||||||
rego.Query("allow = data.problem.rbac.allow"),
|
|
||||||
rego.Load([]string{"./opa/problem.rego"}, nil),
|
|
||||||
).PrepareForEval(context.TODO())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &PermissionService{
|
|
||||||
query: &query,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PermissionService) Allowed(ctx context.Context, user *models.User, action string) bool {
|
|
||||||
input := map[string]interface{}{
|
|
||||||
"user": user,
|
|
||||||
"action": action,
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := s.query.Eval(ctx, rego.EvalInput(input))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return result[0].Bindings["allow"].(bool)
|
|
||||||
}
|
|
|
@ -2,20 +2,22 @@
|
||||||
-- +goose StatementBegin
|
-- +goose StatementBegin
|
||||||
CREATE TABLE IF NOT EXISTS problems
|
CREATE TABLE IF NOT EXISTS problems
|
||||||
(
|
(
|
||||||
id serial NOT NULL,
|
id serial NOT NULL,
|
||||||
title varchar(255) NOT NULL,
|
title varchar(64) NOT NULL,
|
||||||
content varchar(65536) NOT NULL DEFAULT '',
|
legend varchar(10240) NOT NULL DEFAULT '',
|
||||||
time_limit integer NOT NULL DEFAULT 1000,
|
input_format varchar(10240) NOT NULL DEFAULT '',
|
||||||
memory_limit integer NOT NULL DEFAULT 65536,
|
output_format varchar(10240) NOT NULL DEFAULT '',
|
||||||
testing_strategy integer NOT NULL DEFAULT 1,
|
notes varchar(10240) NOT NULL DEFAULT '',
|
||||||
testing_order varchar(1024) NOT NULL DEFAULT '',
|
tutorial varchar(10240) NOT NULL DEFAULT '',
|
||||||
created_at timestamptz NOT NULL DEFAULT now(),
|
latex_summary varchar(10240) NOT NULL DEFAULT '',
|
||||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
time_limit integer NOT NULL DEFAULT 1000,
|
||||||
|
memory_limit integer NOT NULL DEFAULT 65536,
|
||||||
|
created_at timestamptz NOT NULL DEFAULT now(),
|
||||||
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
CHECK (length(title) != 0),
|
CHECK (length(title) != 0),
|
||||||
CHECK (memory_limit > 0),
|
CHECK (memory_limit > 0),
|
||||||
CHECK (time_limit > 0),
|
CHECK (time_limit > 0)
|
||||||
CHECK (testing_strategy > 0)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TRIGGER on_problems_update
|
CREATE TRIGGER on_problems_update
|
||||||
|
@ -26,10 +28,10 @@ EXECUTE PROCEDURE updated_at_update();
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS contests
|
CREATE TABLE IF NOT EXISTS contests
|
||||||
(
|
(
|
||||||
id serial NOT NULL,
|
id serial NOT NULL,
|
||||||
title varchar(255) NOT NULL,
|
title varchar(64) NOT NULL,
|
||||||
created_at timestamptz NOT NULL DEFAULT now(),
|
created_at timestamptz NOT NULL DEFAULT now(),
|
||||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
CHECK (length(title) != 0)
|
CHECK (length(title) != 0)
|
||||||
);
|
);
|
||||||
|
@ -46,11 +48,11 @@ CREATE TABLE IF NOT EXISTS tasks
|
||||||
problem_id integer NOT NULL REFERENCES problems (id),
|
problem_id integer NOT NULL REFERENCES problems (id),
|
||||||
contest_id integer NOT NULL REFERENCES contests (id),
|
contest_id integer NOT NULL REFERENCES contests (id),
|
||||||
position integer NOT NULL,
|
position integer NOT NULL,
|
||||||
prefix varchar(10) NOT NULL,
|
|
||||||
created_at timestamptz NOT NULL DEFAULT now(),
|
created_at timestamptz NOT NULL DEFAULT now(),
|
||||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
UNIQUE (problem_id, contest_id),
|
UNIQUE (problem_id, contest_id),
|
||||||
|
UNIQUE (contest_id, position),
|
||||||
CHECK (position >= 0)
|
CHECK (position >= 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -62,12 +64,12 @@ EXECUTE PROCEDURE updated_at_update();
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS participants
|
CREATE TABLE IF NOT EXISTS participants
|
||||||
(
|
(
|
||||||
id serial NOT NULL,
|
id serial NOT NULL,
|
||||||
user_id integer NOT NULL,
|
user_id integer NOT NULL,
|
||||||
contest_id integer NOT NULL REFERENCES contests (id),
|
contest_id integer NOT NULL REFERENCES contests (id),
|
||||||
name varchar(255) NOT NULL,
|
name varchar(64) NOT NULL,
|
||||||
created_at timestamptz NOT NULL DEFAULT now(),
|
created_at timestamptz NOT NULL DEFAULT now(),
|
||||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
UNIQUE (user_id, contest_id),
|
UNIQUE (user_id, contest_id),
|
||||||
CHECK (length(name) != 0)
|
CHECK (length(name) != 0)
|
||||||
|
@ -86,7 +88,6 @@ CREATE TABLE IF NOT EXISTS solutions
|
||||||
participant_id integer NOT NULL REFERENCES participants (id),
|
participant_id integer NOT NULL REFERENCES participants (id),
|
||||||
solution varchar(1048576) NOT NULL,
|
solution varchar(1048576) NOT NULL,
|
||||||
state integer NOT NULL DEFAULT 1,
|
state integer NOT NULL DEFAULT 1,
|
||||||
results varchar(1000) NOT NULL,
|
|
||||||
score integer NOT NULL,
|
score integer NOT NULL,
|
||||||
penalty integer NOT NULL,
|
penalty integer NOT NULL,
|
||||||
total_score integer NOT NULL,
|
total_score integer NOT NULL,
|
||||||
|
@ -102,25 +103,6 @@ CREATE TRIGGER on_solutions_update
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
EXECUTE PROCEDURE updated_at_update();
|
EXECUTE PROCEDURE updated_at_update();
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS best_solutions
|
|
||||||
(
|
|
||||||
id serial NOT NULL,
|
|
||||||
participant_id integer NOT NULL REFERENCES participants (id),
|
|
||||||
task_id integer NOT NULL REFERENCES tasks (id),
|
|
||||||
solution_id integer NOT NULL REFERENCES solutions (id),
|
|
||||||
best_total_score integer NOT NULL,
|
|
||||||
created_at timestamptz NOT NULL DEFAULT now(),
|
|
||||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
||||||
PRIMARY KEY (id),
|
|
||||||
UNIQUE (participant_id, task_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TRIGGER on_best_solutions_update
|
|
||||||
BEFORE UPDATE
|
|
||||||
ON best_solutions
|
|
||||||
FOR EACH ROW
|
|
||||||
EXECUTE PROCEDURE updated_at_update();
|
|
||||||
|
|
||||||
CREATE FUNCTION updated_at_update() RETURNS TRIGGER
|
CREATE FUNCTION updated_at_update() RETURNS TRIGGER
|
||||||
LANGUAGE plpgsql AS
|
LANGUAGE plpgsql AS
|
||||||
$$
|
$$
|
||||||
|
@ -144,7 +126,5 @@ DROP TRIGGER IF EXISTS on_participants_update ON participants;
|
||||||
DROP TABLE IF EXISTS participants;
|
DROP TABLE IF EXISTS participants;
|
||||||
DROP TRIGGER IF EXISTS on_solutions_update ON solutions;
|
DROP TRIGGER IF EXISTS on_solutions_update ON solutions;
|
||||||
DROP TABLE IF EXISTS solutions;
|
DROP TABLE IF EXISTS solutions;
|
||||||
DROP TRIGGER IF EXISTS on_best_solutions_update ON best_solutions;
|
|
||||||
DROP TABLE IF EXISTS best_solutions;
|
|
||||||
DROP FUNCTION updated_at_update();
|
DROP FUNCTION updated_at_update();
|
||||||
-- +goose StatementEnd
|
-- +goose StatementEnd
|
||||||
|
|
2
proto
2
proto
|
@ -1 +1 @@
|
||||||
Subproject commit e6de2af416b636ffc84d2bedccdc3c79592af1b9
|
Subproject commit c6824ea56aee42b5491fada04eb1f1b33162c1ea
|
Loading…
Reference in a new issue