diff --git a/src/Application/Controller/XMLRPC/Handler.php b/src/Application/Controller/XMLRPC/Handler.php index 2b36bc0..c49a5be 100644 --- a/src/Application/Controller/XMLRPC/Handler.php +++ b/src/Application/Controller/XMLRPC/Handler.php @@ -485,7 +485,7 @@ public function setCommenceTicketState($ticket_id) { throw new Exception(__FUNCTION__.': ticket is not in initial state!',1304); } - $commenceState = ProjectTicketState::getCommenceState($ticket['project_id'], $ticket['ticket_type']); + $commenceState = ProjectTicketState::getCommenceState($ticket_id); if(!$commenceState) { throw new Exception(__FUNCTION__.': ticket has no commence state!',1305); } diff --git a/src/Application/Migrations/01_ticket_states.sql b/src/Application/Migrations/01_ticket_states.sql index 6dc044c..571123b 100644 --- a/src/Application/Migrations/01_ticket_states.sql +++ b/src/Application/Migrations/01_ticket_states.sql @@ -78,59 +78,59 @@ CREATE TRIGGER increment_ticket_state_sort BEFORE INSERT ON tbl_ticket_state FOR -- meta tickets -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('meta', 'staging', 0, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('meta', 'staged', 50, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('meta', 'closed', 50, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('meta', 'staging', 0, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('meta', 'staged', 50, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('meta', 'closed', 50, false, false); -- recording tickets -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'locked', 0, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'scheduled', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'recording', 40, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'recorded', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'preparing', 10, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'prepared', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'cutting', 30, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'cut', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'finalizing', 10, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'finalized', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'ready to archive', 0, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'archiving', 0, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'archived', 0, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'ready to remove', 0, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'removing', 0, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('recording', 'gone', 0, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'locked', 0, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'scheduled', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'recording', 40, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'recorded', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'preparing', 10, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'prepared', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'cutting', 30, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'cut', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'finalizing', 10, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'finalized', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'ready to archive', 0, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'archiving', 0, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'archived', 0, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'ready to remove', 0, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'removing', 0, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('recording', 'gone', 0, false, false); -- encoding tickets -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'material needed', 0, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'ready to encode', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'encoding', 50, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'encoded', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'postencoding', 10, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'postencoded', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'checking', 20, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'checked', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'postprocessing', 10, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'postprocessed', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'ready to release', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'releasing', 20, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'released', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'ready to remove', 0, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'removing', 0, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('encoding', 'gone', 0, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'material needed', 0, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'ready to encode', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'encoding', 50, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'encoded', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'postencoding', 10, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'postencoded', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'checking', 20, false, true); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'checked', 5, false, true); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'postprocessing', 10, true, true); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'postprocessed', 5, false, true); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'ready to release', 5, false, true); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'releasing', 20, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'released', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'ready to remove', 0, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'removing', 0, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('encoding', 'gone', 0, false, false); -- ingest tickets -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'incomplete', 0, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'ready to ingest', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'ingesting', 50, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'ingested', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'finalizing', 10, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'finalized', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'ready to archive', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'archiving', 30, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'archived', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'ready to remove', 5, false); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'removing', 20, true); -INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable) VALUES ('ingest', 'gone', 5, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'incomplete', 0, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'ready to ingest', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'ingesting', 50, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'ingested', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'finalizing', 10, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'finalized', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'ready to archive', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'archiving', 30, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'archived', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'ready to remove', 5, false, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'removing', 20, true, false); +INSERT INTO tbl_ticket_state (ticket_type, ticket_state, percent_progress, service_executable, skippable_on_dependent) VALUES ('ingest', 'gone', 5, false, false); -- mark non-initial states by giving sort <= 0 UPDATE tbl_ticket_state SET sort = 0 where ticket_state = 'locked'; diff --git a/src/Application/Migrations/04_projects.sql b/src/Application/Migrations/04_projects.sql index cd9037b..8326a34 100644 --- a/src/Application/Migrations/04_projects.sql +++ b/src/Application/Migrations/04_projects.sql @@ -50,6 +50,7 @@ CREATE TABLE tbl_project_ticket_state ticket_type enum_ticket_type NOT NULL, ticket_state enum_ticket_state NOT NULL, service_executable boolean NOT NULL DEFAULT false, + skip_on_dependent boolean NOT NULL DEFAULT false, CONSTRAINT tbl_project_ticket_state_pk PRIMARY KEY (project_id, ticket_type, ticket_state), CONSTRAINT tbl_project_ticket_state_project_fk FOREIGN KEY (project_id) REFERENCES tbl_project (id) MATCH SIMPLE diff --git a/src/Application/Migrations/06_tickets.sql b/src/Application/Migrations/06_tickets.sql index 9d70d57..3a25467 100644 --- a/src/Application/Migrations/06_tickets.sql +++ b/src/Application/Migrations/06_tickets.sql @@ -40,7 +40,7 @@ $BODY$ DECLARE next_state record; BEGIN - next_state := ticket_state_next(NEW.project_id, NEW.ticket_type, NEW.ticket_state); + next_state := ticket_state_next(NEW.id, NEW.ticket_state); NEW.ticket_state_next := next_state.ticket_state; NEW.service_executable := next_state.service_executable; @@ -95,7 +95,7 @@ $BODY$ (progress, ticket_state_next, service_executable) = (tp, (n).ticket_state, (n).service_executable) FROM ( - SELECT id, ticket_state_next(t2.project_id, t2.ticket_type, t2.ticket_state) AS n, ticket_progress(t2.id) as tp + SELECT id, ticket_state_next(t2.id) AS n, ticket_progress(t2.id) as tp FROM tbl_ticket t2 WHERE t2.project_id = param_project_id AND param_project_id IS NOT NULL ) AS x diff --git a/src/Application/Migrations/15_function_ticket_state.sql b/src/Application/Migrations/15_function_ticket_state.sql index f72907e..61e9713 100644 --- a/src/Application/Migrations/15_function_ticket_state.sql +++ b/src/Application/Migrations/15_function_ticket_state.sql @@ -2,7 +2,7 @@ BEGIN; SET ROLE TO postgres; -CREATE OR REPLACE FUNCTION ticket_state_next(param_project_id bigint, param_ticket_type enum_ticket_type, param_ticket_state enum_ticket_state) +CREATE OR REPLACE FUNCTION ticket_state_next(param_ticket_id bigint, param_ticket_state enum_ticket_state DEFAULT NULL) RETURNS TABLE(ticket_state enum_ticket_state, service_executable boolean) AS $$ DECLARE @@ -11,26 +11,35 @@ BEGIN SELECT pts.ticket_state, pts.service_executable FROM - tbl_ticket_state ts1 + tbl_ticket t JOIN - tbl_project_ticket_state pts ON pts.ticket_type = ts1.ticket_type AND pts.ticket_state = ts1.ticket_state + tbl_ticket_state ts_this ON ts_this.ticket_type = t.ticket_type AND ts_this.ticket_state = COALESCE(param_ticket_state, t.ticket_state) JOIN - tbl_ticket_state ts2 ON ts1.ticket_type = ts2.ticket_type AND ts1.sort > ts2.sort + tbl_project_ticket_state pts ON pts.project_id = t.project_id AND pts.ticket_type = t.ticket_type + JOIN + tbl_ticket_state ts_other ON ts_other.ticket_type = pts.ticket_type AND ts_other.ticket_state = pts.ticket_state WHERE - pts.project_id = param_project_id AND - ts2.ticket_type = param_ticket_type AND - ts2.ticket_state = param_ticket_state - ORDER BY - ts1.sort ASC + t.id = param_ticket_id AND + ts_other.sort > ts_this.sort AND + (pts.skip_on_dependent = FALSE OR + ( /* is master encoding ticket */ + SELECT ep.depends_on + FROM tbl_ticket t + INNER JOIN tbl_encoding_profile_version epv ON epv.id = t.encoding_profile_version_id + INNER JOIN tbl_encoding_profile ep ON ep.id = epv.encoding_profile_id + WHERE t.id = param_ticket_id + ) IS NULL ) + ORDER BY ts_other.sort ASC LIMIT 1; - IF NOT FOUND THEN - RETURN QUERY SELECT NULL::enum_ticket_state, false; - END IF; + + IF NOT FOUND THEN + RETURN QUERY SELECT NULL::enum_ticket_state, false; + END IF; END $$ LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION ticket_state_previous(param_project_id bigint, param_ticket_type enum_ticket_type, param_ticket_state enum_ticket_state) +CREATE OR REPLACE FUNCTION ticket_state_previous(param_ticket_id bigint, param_ticket_state enum_ticket_state DEFAULT NULL) RETURNS TABLE(ticket_state enum_ticket_state, service_executable boolean) AS $$ DECLARE @@ -39,21 +48,30 @@ BEGIN SELECT pts.ticket_state, pts.service_executable FROM - tbl_ticket_state ts1 + tbl_ticket t + JOIN + tbl_ticket_state ts_this ON ts_this.ticket_type = t.ticket_type AND ts_this.ticket_state = COALESCE(param_ticket_state, t.ticket_state) JOIN - tbl_project_ticket_state pts ON pts.ticket_type = ts1.ticket_type AND pts.ticket_state = ts1.ticket_state + tbl_project_ticket_state pts ON pts.project_id = t.project_id AND pts.ticket_type = t.ticket_type JOIN - tbl_ticket_state ts2 ON ts1.ticket_type = ts2.ticket_type AND ts1.sort < ts2.sort + tbl_ticket_state ts_other ON ts_other.ticket_type = pts.ticket_type AND ts_other.ticket_state = pts.ticket_state WHERE - pts.project_id = param_project_id AND - ts2.ticket_type = param_ticket_type AND - ts2.ticket_state = param_ticket_state - ORDER BY - ts1.sort DESC + t.id = param_ticket_id AND + ts_other.sort < ts_this.sort AND + (pts.skip_on_dependent = FALSE OR + ( /* is master encoding ticket */ + SELECT ep.depends_on + FROM tbl_ticket t + JOIN tbl_encoding_profile_version epv ON epv.id = t.encoding_profile_version_id + JOIN tbl_encoding_profile ep ON ep.id = epv.encoding_profile_id + WHERE t.id = param_ticket_id + ) IS NULL ) + ORDER BY ts_other.sort DESC LIMIT 1; - IF NOT FOUND THEN - RETURN QUERY SELECT NULL::enum_ticket_state, false; - END IF; + + IF NOT FOUND THEN + RETURN QUERY SELECT NULL::enum_ticket_state, false; + END IF; END $$ LANGUAGE plpgsql; @@ -96,22 +114,31 @@ END $$ LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION ticket_state_commence(param_project_id bigint, param_ticket_type enum_ticket_type) +CREATE OR REPLACE FUNCTION ticket_state_commence(param_ticket_id bigint) RETURNS enum_ticket_state AS $$ DECLARE + var_project_id bigint; + var_ticket_type enum_ticket_type; ret enum_ticket_state; next_state record; BEGIN + SELECT + project_id, ticket_type INTO var_project_id, var_ticket_type + FROM + tbl_ticket t + WHERE + t.id = param_ticket_id; + -- special case: meta ticket, since it has no serviceable states - IF param_ticket_type = 'meta' THEN + IF var_ticket_type = 'meta' THEN RETURN 'staged'::enum_ticket_state; END IF; - ret := (SELECT ticket_state_initial(param_project_id, param_ticket_type)); + ret := (SELECT ticket_state_initial(var_project_id, var_ticket_type)); WHILE ret IS NOT NULL LOOP - SELECT * INTO next_state FROM ticket_state_next(param_project_id, param_ticket_type, ret); + SELECT * INTO next_state FROM ticket_state_next(param_ticket_id, ret); IF NOT FOUND THEN ret := NULL; EXIT; @@ -215,4 +242,4 @@ END $$ LANGUAGE plpgsql; -COMMIT; \ No newline at end of file +COMMIT; diff --git a/src/Application/Migrations/__2019-09-29_skip_dependent.sql b/src/Application/Migrations/__2019-09-29_skip_dependent.sql new file mode 100644 index 0000000..074819c --- /dev/null +++ b/src/Application/Migrations/__2019-09-29_skip_dependent.sql @@ -0,0 +1,184 @@ +BEGIN; + +SET ROLE TO postgres; + +ALTER TABLE tbl_project_ticket_state + ADD COLUMN skip_on_dependent boolean NOT NULL DEFAULT false; + +ALTER TABLE tbl_ticket_state + ADD COLUMN skippable_on_dependent boolean NOT NULL DEFAULT false; + + +UPDATE tbl_ticket_state +SET skippable_on_dependent = true +WHERE ticket_type = 'encoding' + AND ticket_state IN ('checking', 'checked', 'postprocessing', 'postprocessed', 'ready to release'); + +DROP FUNCTION IF EXISTS ticket_state_next(bigint); +DROP FUNCTION IF EXISTS ticket_state_next(bigint, enum_ticket_type); +DROP FUNCTION IF EXISTS ticket_state_next(bigint, enum_ticket_type, enum_ticket_state); + +DROP FUNCTION IF EXISTS ticket_state_previous(bigint); +DROP FUNCTION IF EXISTS ticket_state_previous(bigint, enum_ticket_type); +DROP FUNCTION IF EXISTS ticket_state_previous(bigint, enum_ticket_type, enum_ticket_state); + +DROP FUNCTION IF EXISTS ticket_state_commence(bigint, enum_ticket_type); +DROP FUNCTION IF EXISTS ticket_state_commence(bigint); + + +CREATE OR REPLACE FUNCTION update_ticket_next_state() + RETURNS trigger AS +$BODY$ + DECLARE + next_state record; + BEGIN + next_state := ticket_state_next(NEW.id, NEW.ticket_state); + + NEW.ticket_state_next := next_state.ticket_state; + NEW.service_executable := next_state.service_executable; + + RETURN NEW; + END +$BODY$ +LANGUAGE plpgsql VOLATILE; + + +CREATE OR REPLACE FUNCTION update_all_tickets_progress_and_next_state(param_project_id bigint) + RETURNS VOID AS +$BODY$ + BEGIN + + UPDATE tbl_ticket t SET + (progress, ticket_state_next, service_executable) + = (tp, (n).ticket_state, (n).service_executable) + FROM ( + SELECT id, ticket_state_next(t2.id) AS n, ticket_progress(t2.id) as tp + FROM tbl_ticket t2 + WHERE t2.project_id = param_project_id AND param_project_id IS NOT NULL + ) AS x + WHERE t.id = x.id; + + END; +$BODY$ +LANGUAGE plpgsql VOLATILE; + + +CREATE OR REPLACE FUNCTION ticket_state_next(param_ticket_id bigint, param_ticket_state enum_ticket_state DEFAULT NULL) + RETURNS TABLE(ticket_state enum_ticket_state, service_executable boolean) AS + $$ +DECLARE +BEGIN + RETURN QUERY + SELECT + pts.ticket_state, pts.service_executable + FROM + tbl_ticket t + JOIN + tbl_ticket_state ts_this ON ts_this.ticket_type = t.ticket_type AND ts_this.ticket_state = COALESCE(param_ticket_state, t.ticket_state) + JOIN + tbl_project_ticket_state pts ON pts.project_id = t.project_id AND pts.ticket_type = t.ticket_type + JOIN + tbl_ticket_state ts_other ON ts_other.ticket_type = pts.ticket_type AND ts_other.ticket_state = pts.ticket_state + WHERE + t.id = param_ticket_id AND + ts_other.sort > ts_this.sort AND + (pts.skip_on_dependent = FALSE OR + ( /* is master encoding ticket */ + SELECT ep.depends_on + FROM tbl_ticket t + INNER JOIN tbl_encoding_profile_version epv ON epv.id = t.encoding_profile_version_id + INNER JOIN tbl_encoding_profile ep ON ep.id = epv.encoding_profile_id + WHERE t.id = param_ticket_id + ) IS NULL ) + ORDER BY ts_other.sort ASC + LIMIT 1; + + IF NOT FOUND THEN + RETURN QUERY SELECT NULL::enum_ticket_state, false; + END IF; +END +$$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION ticket_state_previous(param_ticket_id bigint, param_ticket_state enum_ticket_state DEFAULT NULL) + RETURNS TABLE(ticket_state enum_ticket_state, service_executable boolean) AS + $$ +DECLARE +BEGIN + RETURN QUERY + SELECT + pts.ticket_state, pts.service_executable + FROM + tbl_ticket t + JOIN + tbl_ticket_state ts_this ON ts_this.ticket_type = t.ticket_type AND ts_this.ticket_state = COALESCE(param_ticket_state, t.ticket_state) + JOIN + tbl_project_ticket_state pts ON pts.project_id = t.project_id AND pts.ticket_type = t.ticket_type + JOIN + tbl_ticket_state ts_other ON ts_other.ticket_type = pts.ticket_type AND ts_other.ticket_state = pts.ticket_state + WHERE + t.id = param_ticket_id AND + ts_other.sort < ts_this.sort AND + (pts.skip_on_dependent = FALSE OR + ( /* is master encoding ticket */ + SELECT ep.depends_on + FROM tbl_ticket t + JOIN tbl_encoding_profile_version epv ON epv.id = t.encoding_profile_version_id + JOIN tbl_encoding_profile ep ON ep.id = epv.encoding_profile_id + WHERE t.id = param_ticket_id + ) IS NULL ) + ORDER BY ts_other.sort DESC + LIMIT 1; + + IF NOT FOUND THEN + RETURN QUERY SELECT NULL::enum_ticket_state, false; + END IF; +END +$$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION ticket_state_commence(param_ticket_id bigint) + RETURNS enum_ticket_state AS +$$ +DECLARE + var_project_id bigint; + var_ticket_type enum_ticket_type; + ret enum_ticket_state; + next_state record; +BEGIN + SELECT + project_id, ticket_type INTO var_project_id, var_ticket_type + FROM + tbl_ticket t + WHERE + t.id = param_ticket_id; + + -- special case: meta ticket, since it has no serviceable states + IF var_ticket_type = 'meta' THEN + RETURN 'staged'::enum_ticket_state; + END IF; + + ret := (SELECT ticket_state_initial(var_project_id, var_ticket_type)); + + WHILE ret IS NOT NULL LOOP + SELECT * INTO next_state FROM ticket_state_next(param_ticket_id, ret); + IF NOT FOUND THEN + ret := NULL; + EXIT; + END IF; + + -- exit, if serviceable state is found + EXIT WHEN next_state.service_executable IS TRUE; + + -- otherwise set current state as possible commence state + ret := next_state.ticket_state; + END LOOP; + + RETURN ret; +END +$$ +LANGUAGE plpgsql; + + +COMMIT; diff --git a/src/Application/Model/ProjectTicketState.php b/src/Application/Model/ProjectTicketState.php index 89226f9..3e55781 100644 --- a/src/Application/Model/ProjectTicketState.php +++ b/src/Application/Model/ProjectTicketState.php @@ -20,31 +20,10 @@ class ProjectTicketState extends Model { ] ]; - // TODO: use Ticket::queryNextState / queryPreviousState? - public static function getNextState($project, $type, $state) { + public static function getCommenceState($ticket) { $handle = Database::$Instance->query( - 'SELECT * FROM ticket_state_next(?, ?, ?)', - [$project, $type, $state] - ); - $row = $handle->fetch(); - - return ($row === false)? null : $row; - } - - public static function getPreviousState($project, $type, $state) { - $handle = Database::$Instance->query( - 'SELECT * FROM ticket_state_previous(?, ?, ?)', - [$project, $type, $state] - ); - - $row = $handle->fetch(); - return ($row === false)? null : $row; - } - - public static function getCommenceState($project, $type) { - $handle = Database::$Instance->query( - 'SELECT ticket_state_commence(?, ?)', - [$project, $type] + 'SELECT ticket_state_commence(?)', + [$ticket] ); return $handle->fetch()['ticket_state_commence']; diff --git a/src/Application/Model/Ticket.php b/src/Application/Model/Ticket.php index 2678f1f..29d1e7a 100644 --- a/src/Application/Model/Ticket.php +++ b/src/Application/Model/Ticket.php @@ -904,13 +904,9 @@ public function queryPreviousState($state = null) { return (new Database_Query('')) ->select('ticket_state') ->from( - 'ticket_state_previous(?, ?, ?)', + 'ticket_state_previous(?)', 'previous_state', - [ - $this['project_id'], - $this['ticket_type'], - ($state === null)? $this['ticket_state'] : $state - ] + [$this['id']] ); } @@ -918,16 +914,12 @@ public function queryNextState($state = null) { return (new Database_Query('')) ->select('ticket_state') ->from( - 'ticket_state_next(?, ?, ?)', + 'ticket_state_next(?)', 'next_state', - [ - $this['project_id'], - $this['ticket_type'], - ($state === null)? $this['ticket_state'] : $state - ] + [$this['id']] ); } - + public function findNextForAction($state) { $next = null; diff --git a/src/Application/Model/TicketState.php b/src/Application/Model/TicketState.php index 8d195cb..dccc0f7 100644 --- a/src/Application/Model/TicketState.php +++ b/src/Application/Model/TicketState.php @@ -9,7 +9,9 @@ class TicketState extends Model { public $hasOne = [ 'ProjectTicketState' => [ 'foreign_key' => ['ticket_type', 'ticket_state'], - 'select' => '(ticket_state IS NOT NULL) AS project_enabled, service_executable AS project_service_executable' + 'select' => '(ticket_state IS NOT NULL) AS project_enabled,' . + 'service_executable AS project_service_executable,' . + 'skip_on_dependent AS project_skip_on_dependent' ] ]; diff --git a/src/Application/View/projects/settings/states.html.php b/src/Application/View/projects/settings/states.html.php index 4b231c7..6a7b3fa 100644 --- a/src/Application/View/projects/settings/states.html.php +++ b/src/Application/View/projects/settings/states.html.php @@ -2,7 +2,7 @@ render('projects/settings/_header'); ?> +$first = false; ?> $project['read_only']]); ?>
@@ -17,54 +17,74 @@ $encodingStates, (!empty($project))? $project['dependee_ticket_trigger_state'] : null) ?>
- $state): ?> - 1): - $typeRows = 0; ?> - - - - -
- - - - - - - - - - +
+
TypeStateService
+ - - + + + + + + + $state) { + if ($state['ticket_type'] === 'encoding') { + continue; + } + + if ($type !== $state['ticket_type']) { + $type = $state['ticket_type']; + $first = true; + } else { + $first = false; + } + + + echo $this->render('projects/settings/states/_state', [ + 'f' => $f, + 'first' => $first, + 'index' => $index, + 'state' => $state + ]); + } ?> + +
TypeStateService
+
+
+ + - - - - - - register('States[' . $index . '][_destroy]'); ?> - + + + + + + + + $state) { + if ($state['ticket_type'] !== 'encoding') { + continue; + } + + if ($type !== $state['ticket_type']) { + $type = $state['ticket_type']; + $first = true; + } else { + $first = false; + } + + + echo $this->render('projects/settings/states/_state', [ + 'f' => $f, + 'first' => $first, + 'index' => $index, + 'state' => $state, + 'skip' => true + ]); + } ?>
checkbox( - 'States[' . $index . '][ticket_state]', - $state['ticket_state'], - $state['project_enabled'], - ['value' => $state['ticket_state']] + - (($state['project_enabled'])? - ['data-association-destroy' => 'States[' . $index . '][_destroy]'] : - []), - false - ) . - $f->hidden('States[' . $index . '][ticket_type]', $state['ticket_type']); - ?>checkbox('States[' . $index . '][service_executable]', null, $state['project_service_executable'], [], false); - } ?>
TypeStateService + Skip +
diff --git a/src/Application/View/projects/settings/states/_state.html.php b/src/Application/View/projects/settings/states/_state.html.php new file mode 100644 index 0000000..b8a1f41 --- /dev/null +++ b/src/Application/View/projects/settings/states/_state.html.php @@ -0,0 +1,30 @@ + + + + + + + + checkbox( + 'States[' . $index . '][ticket_state]', + $state['ticket_state'], + $state['project_enabled'], + ['value' => $state['ticket_state']] + + (($state['project_enabled'])? + ['data-association-destroy' => 'States[' . $index . '][_destroy]'] : + []), + false + ) . + $f->hidden('States[' . $index . '][ticket_type]', $state['ticket_type']); + ?> + checkbox('States[' . $index . '][service_executable]', null, $state['project_service_executable'], [], false); + } ?> + + checkbox('States[' . $index . '][skip_on_dependent]', null, $state['project_skip_on_dependent'], ['title' => 'This state will be skipped in dependent encoding profiles'], false); + } ?> + + +register('States[' . $index . '][_destroy]'); ?>