Changes between Version 2 and Version 3 of DatabaseProgramming


Ignore:
Timestamp:
06/15/26 20:32:17 (4 days ago)
Author:
231067
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • DatabaseProgramming

    v2 v3  
    292292
    293293== Тригери
     294
     295Тригерот `trg_anti_spam_chat`, кој ја извршува тригер функцијата `fn_enforce_chat_security`, дејствува пред секое внесување на нова порака во табелата со цел да обезбеди безбедност и заштита од несакани содржини. Првиот чекор на овој механизам е да провери дали корисникот кој се обидува да ја испрати пораката е всушност заведен како студент или ментор во конкретниот разговор, со што се спречува неовластен пристап и упад од надворешни лица. Вториот чекор претставува заштита против спам која пресметува колку пораки испратил истиот корисник во тој разговор во последните 5 минути. Доколку овој број го надмине лимитот од 10 пораки, тригерот автоматски го блокира внесувањето и исфрла безбедносен исклучок.
     296
     297{{{
     298CREATE OR REPLACE FUNCTION fn_enforce_chat_security()
     299RETURNS TRIGGER AS $$
     300DECLARE
     301    v_chat_owner_student BIGINT;
     302    v_chat_owner_mentor BIGINT;
     303    v_recent_messages INT;
     304BEGIN
     305    -- 1. Валидација на пристап (Дали е овластен за овој чет?)
     306    SELECT StudentID, MentorID INTO v_chat_owner_student, v_chat_owner_mentor
     307    FROM Chat WHERE ID = NEW.ChatID;
     308
     309    IF NEW.UserID != v_chat_owner_student AND NEW.UserID != v_chat_owner_mentor THEN
     310        RAISE EXCEPTION 'ГРЕШКА: Безбедносен прекршок! Корисникот % не е учесник во чет %.', NEW.UserID, NEW.ChatID;
     311    END IF;
     312
     313    -- 2. Anti-Spam Заштита (Макс 10 пораки во 5 минути)
     314    SELECT COUNT(*) INTO v_recent_messages FROM Message
     315    WHERE UserID = NEW.UserID AND ChatID = NEW.ChatID AND Timestamp > (NOW() - INTERVAL '5 minutes');
     316
     317    IF v_recent_messages >= 10 THEN
     318        RAISE EXCEPTION 'ПРЕДУПРЕДУВАЊЕ: Го надминавте лимитот за праќање пораки. Обидете се подоцна!';
     319    END IF;
     320
     321    RETURN NEW;
     322END;
     323$$ LANGUAGE plpgsql;
     324
     325DROP TRIGGER IF EXISTS trg_anti_spam_chat ON Message;
     326CREATE TRIGGER trg_anti_spam_chat
     327BEFORE INSERT ON Message
     328FOR EACH ROW EXECUTE FUNCTION fn_enforce_chat_security();
     329
     330
     331-- ТЕСТИРАЊЕ
     332INSERT INTO Message (Content, isRead, Timestamp, ChatID, UserID) VALUES ('Тест спам порака', false, NOW(), 5, 1);
     333
     334--INSERT INTO Chat (Title, Topic, Status, "Date", StudentID, MentorID) VALUES ('Тест разговор за спам', 'Комуникација', 0, NOW(), 500, 300);
     335
     336}}}
     337
     338----
     339
     340Тригерот `trg_strict_task_timeline`, придружен со функцијата `fn_guard_task_timeline`, е задолжен за одржување на временскиот интегритет на задачите и се активира пред секое внесување или ажурирање на податоците во табелата за задачи. Тој забранува поставување на краен рок кој е еднаков или пред почетниот датум на задачата. Дополнително, при креирање на сосема нова задача, тригерот не дозволува нејзиниот краен рок да биде поставен во минатото во однос на тековниот ден. Исто така, доколку се прави обид за ажурирање на задача која веќе е завршена, тригерот ја одбива промената на крајниот рок со цел да ги заклучи минатите временски рамки.
     341
     342{{{
     343CREATE OR REPLACE FUNCTION fn_guard_task_timeline()
     344RETURNS TRIGGER AS $$
     345BEGIN
     346    -- Дали EndDate е пред StartDate?
     347    IF NEW.EndDate <= NEW.StartDate THEN
     348        RAISE EXCEPTION 'ГРЕШКА: Крајниот рок мора да биде по почетниот датум!';
     349    END IF;
     350
     351    -- Ако е ВНЕСУВАЊЕ, не смее крајниот рок да е во минатото
     352    IF TG_OP = 'INSERT' AND NEW.EndDate < CURRENT_DATE THEN
     353        RAISE EXCEPTION 'ГРЕШКА: Не можете да креирате нова задача со краен рок во минатото!';
     354    END IF;
     355
     356    -- Ако е АЖУРИРАЊЕ и задачата е веќе завршена
     357    IF TG_OP = 'UPDATE' AND OLD.Status = 1 AND NEW.EndDate != OLD.EndDate THEN
     358        RAISE EXCEPTION 'ОДБИЕНО: Задачата е веќе завршена. Временските рамки се заклучени!';
     359    END IF;
     360
     361    RETURN NEW;
     362END;
     363$$ LANGUAGE plpgsql;
     364
     365DROP TRIGGER IF EXISTS trg_strict_task_timeline ON Task;
     366CREATE TRIGGER trg_strict_task_timeline
     367BEFORE INSERT OR UPDATE ON Task
     368FOR EACH ROW EXECUTE FUNCTION fn_guard_task_timeline();
     369
     370
     371-- ТЕСТИРАЊЕ
     372INSERT INTO Task (MentorshipID, description , StartDate, EndDate, Status) VALUES (1, 'Невалидна Задача', NOW(), NOW() - INTERVAL '7 days', 0);
     373
     374}}}
     375
     376----
     377
     378Тригерот `trg_topic_state_machine` ја извршува функцијата `fn_topic_state_guard` пред секое ажурирање на податоците во табелата за предложени теми за менторство со цел да го контролира и заштити животниот циклус на темите. При обид за менување на матичниот предмет на кој му припаѓа веќе креирана тема, овој механизам ја прекинува операцијата и исфрла грешка за да спречи конфузија во наставната програма. Дополнително, тригерот спречува рачно менување на статусот на темата од зафатена во слободна доколку таа тема сè уште е поврзана со некое активно менторство кое содржи незавршени задачи, со што се гарантира дека темите нема предвремено и нелогично да се ослободат во системот.
     379
     380{{{
     381
     382CREATE OR REPLACE FUNCTION fn_topic_state_guard()
     383RETURNS TRIGGER AS $$
     384DECLARE
     385    v_active_mentorships INT;
     386BEGIN
     387    -- Забрането менување на предмет откако темата е креирана
     388    IF TG_OP = 'UPDATE' AND OLD.SubjectID != NEW.SubjectID THEN
     389        RAISE EXCEPTION 'ПРЕДУПРЕДУВАЊЕ: Откако темата е предложена, забрането е менување на нејзиниот предмет!';
     390    END IF;
     391
     392    -- Ако некој рачно пробува да ја ослободи темата (isAvailable -> true)
     393    IF TG_OP = 'UPDATE' AND OLD.isAvailable = false AND NEW.isAvailable = true THEN
     394        SELECT COUNT(*) INTO v_active_mentorships FROM Mentorship m
     395        JOIN Task t ON m.ID = t.MentorshipID
     396        WHERE m.TopicSuggestionID = NEW.ID AND t.Status != 1;
     397       
     398        IF v_active_mentorships > 0 THEN
     399            RAISE EXCEPTION 'ПРЕДУПРЕДУВАЊЕ: Темата не може да се ослободи бидејќи сè уште е поврзана со активно менторство!';
     400        END IF;
     401    END IF;
     402
     403    RETURN NEW;
     404END;
     405$$ LANGUAGE plpgsql;
     406
     407DROP TRIGGER IF EXISTS trg_topic_state_machine ON TopicSuggestion;
     408CREATE TRIGGER trg_topic_state_machine
     409BEFORE UPDATE ON TopicSuggestion
     410FOR EACH ROW EXECUTE FUNCTION fn_topic_state_guard();
     411
     412-- ТЕСТИРАЊЕ
     413UPDATE TopicSuggestion SET SubjectID = 99999 WHERE ID = (SELECT ID FROM TopicSuggestion LIMIT 1);
     414UPDATE TopicSuggestion SET isAvailable = true WHERE ID = (SELECT TopicSuggestionID FROM Mentorship LIMIT 1);
     415--UPDATE TopicSuggestion SET isAvailable = true WHERE ID = (SELECT m.TopicSuggestionID FROM Mentorship m JOIN Task t ON m.ID = t.MentorshipID WHERE t.Status != 1 LIMIT 1);
     416
     417}}}