= !UseCase: Регистрација на корисник = == Актер == Ненајавен корисник == Цел == Корисникот сака да се регистрира во системот. == Предуслов: измени во DDL == Регистрацијата е двофазна — прво се создава корисник само со мејл и лозинка, а личните податоци се пополнуваат подоцна. Во моменталната шема `name`, `work_position` и `company_size` се `NOT NULL`, што го прави тоа невозможно. Истото важи и за `account.name`. {{{ ALTER TABLE account ALTER COLUMN name DROP NOT NULL; ALTER TABLE "user" ALTER COLUMN name DROP NOT NULL; ALTER TABLE "user" ALTER COLUMN work_position DROP NOT NULL; ALTER TABLE "user" ALTER COLUMN company_size DROP NOT NULL; -- is_profile_complete = true значи дека сите полиња се пополнети ALTER TABLE "user" ADD CONSTRAINT ck_user_profile_complete CHECK ( NOT is_profile_complete OR (name IS NOT NULL AND work_position IS NOT NULL AND company_size IS NOT NULL) ); }}} == Главен тек == * На корисникот му се прикажува почетната страна на Shifter [[Image(home_page.png, 800px)]] * На корисникот му се прикажува страната за регистрација [[Image(register_page.png, 800px)]] * Корисникот ги пополнува полињата за регистрација и кликнува на копчето Create Account [[Image(register_page_filled.png, 800px)]] * На корисникот му се прикажува порака за успешно испратен линк за потврда на неговата мејл адресата. Во базата се креира сметка, иницијален корисник и верификациски токен. {{{ BEGIN; WITH new_account AS ( INSERT INTO account (email, password_hash, name) VALUES ('borjan.gjorgjievski@students.finki.ukim.mk', 'hashed_password_example', NULL) RETURNING id ), new_user AS ( INSERT INTO "user" (account_id, email, password_hash, login_provider, is_verified, is_profile_complete, has_used_free_consultation, points) SELECT id, 'borjan.gjorgjievski@students.finki.ukim.mk', 'hashed_password_example', 'local', FALSE, FALSE, FALSE, 0 FROM new_account RETURNING user_id ) INSERT INTO verification_token (verification_token_uuid, user_id, created_at, expires_at) SELECT 'd9cafe62-760f-44ae-8f79-8f4048414642'::uuid, user_id, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP + INTERVAL '30 minutes' FROM new_user; COMMIT; }}} [[Image(register_page_success.png, 800px)]] * При клик на линкот кој е испратен до неговата мејл адреса, токенот се проверува и корисникот се означува како верификуван. {{{ BEGIN; WITH valid_token AS ( SELECT user_id FROM verification_token WHERE verification_token_uuid = 'd9cafe62-760f-44ae-8f79-8f4048414642'::uuid AND expires_at > CURRENT_TIMESTAMP ) UPDATE "user" u SET is_verified = TRUE FROM valid_token vt WHERE u.user_id = vt.user_id; -- искористениот токен повеќе не е потребен DELETE FROM verification_token WHERE verification_token_uuid = 'd9cafe62-760f-44ae-8f79-8f4048414642'::uuid; COMMIT; }}} * На корисникот му се прикажува страната за персонализација [[Image(personalize_page.png, 800px)]] * Корисникот ги пополнува полињата за персонализација и кликнува на копчето Start Using Shifter. Во базата се ажурираат полињата за персонализација. {{{ BEGIN; UPDATE "user" SET name = 'Borjan Gjorgjievski', work_position = 'Sales & Digital Solutions', company_size = 'freelance', is_profile_complete = TRUE WHERE user_id = :user_id; -- account.name е дупликат на "user".name и мора да се одржува рачно UPDATE account SET name = 'Borjan Gjorgjievski' WHERE id = (SELECT account_id FROM "user" WHERE user_id = :user_id); COMMIT; }}} [[Image(personalize_page_filled.png, 800px)]] * На корисникот му се прикажува почетната страна на Shifter, каде тој е веќе логиран [[Image(home_page_logged_in.png, 800px)]] == Алтернативен тек == * Доколку веќе постои корисник со истата емаил адреса, при обид за регистрација му се прикажува порака за грешка на корисникот. {{{ SELECT EXISTS ( SELECT 1 FROM account WHERE email = 'borjan.gjorgjievski@students.finki.ukim.mk' ) AS email_taken; }}} Ограничувањата `uq_account_email` и `uq_user_email` го спречуваат дуплирањето и на ниво на база, па апликацијата мора да ја фати грешката `23505` доколку два барања стигнат истовремено. * Доколку на корисникот му истекол токенот за валидација на неговата емаил адреса, тогаш откако ќе го кликне линкот за валидација ќе му се прикаже порака дека токенот е истечен и копче за повторно испраќање на нов токен за валидација. {{{ -- проверка на статусот на токенот SELECT user_id, expires_at, (expires_at > CURRENT_TIMESTAMP) AS is_valid FROM verification_token WHERE verification_token_uuid = 'd9cafe62-760f-44ae-8f79-8f4048414642'::uuid; -- повторно испраќање: старите токени се бришат, се креира нов BEGIN; DELETE FROM verification_token WHERE user_id = :user_id; INSERT INTO verification_token (user_id, created_at, expires_at) VALUES (:user_id, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP + INTERVAL '30 minutes') RETURNING verification_token_uuid; COMMIT; }}} == Забелешки == - `company_size` е PostgreSQL enum со мали букви (`freelance`, `micro`, `small`, `medium`, `mid_market`, `enterprise`, `other`). Вредноста `'Freelance'` предизвикува грешка. - Шемата нема колона `deleted` на `"user"` — не постои soft delete. - `email` и `password_hash` постојат и во `account` и во `"user"`. Регистрацијата ги запишува двапати, а секоја промена на лозинка мора да ажурира две табели. Ова треба да се реши на ниво на шема. - При повторно испраќање на токен, `gen_random_uuid()` го генерира UUID-то автоматски — не треба да се внесува рачно.