Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User profile end-of-life #928

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions schema/patches/5.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
BEGIN;

ALTER TABLE public.member
ADD COLUMN eol_state SMALLINT DEFAULT 0;

COMMENT ON COLUMN public.member.eol_state
IS 'The end-of-life status of this profile. 0 is none, 10 deactivated, 20 archived. 1, 2, 3 are pending deactivated, archived, deleted';

ALTER TABLE public.member
ADD COLUMN eol_requested_at TIMESTAMPTZ NULL DEFAULT NULL;

COMMENT ON COLUMN public.member.eol_requested_at
IS 'The time that this member''s profile EOL was requested.';

COMMIT;
9 changes: 8 additions & 1 deletion src/Classes/ServiceAPI/MyRadio_Creditable.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
namespace MyRadio\ServiceAPI;

use MyRadio\MyRadioException;
use MyRadio\ServiceAPI\MyRadio_User;
use MyRadio\ServiceAPI\MyRadio_Scheduler;

Expand Down Expand Up @@ -210,7 +211,13 @@ private function addNewCredits($old, $new, $table, $pkey)
foreach ($new as $credit) {
//Look for an existing credit
if (!in_array($credit, $old)) {
//Doesn't seem to exist.
// Doesn't seem to exist.
// Double-check they're not EOL'd
$creditedUser = MyRadio_User::getInstance($credit['memberid']);
if ($creditedUser->getEolState() >= MyRadio_User::EOL_STATE_DEACTIVATED) {
$name = $creditedUser->getName();
throw new MyRadioException("Cannot credit $name as their profile is deactivated or archived.", 400);
}
self::$db->query(
'INSERT INTO '.$table.' ('.$pkey.', credit_type_id, creditid, effective_from,'
.'memberid, approvedid) VALUES ($1, $2, $3, NOW(), $4, $4)',
Expand Down
123 changes: 118 additions & 5 deletions src/Classes/ServiceAPI/MyRadio_User.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class MyRadio_User extends ServiceAPI implements APICaller
{
use MyRadio_APICaller_Common;

public const EOL_STATE_NONE = 0;
public const EOL_STATE_DEACTIVATED = 10;
public const EOL_STATE_ARCHIVED = 20;

/**
* Stores the currently logged in User's object after first use.
* @var MyRadio_User|boolean
Expand Down Expand Up @@ -175,7 +179,7 @@ class MyRadio_User extends ServiceAPI implements APICaller

/**
* Users radio time, calculated from signed in shows
*
*
* @var mixed
*/
private $radioTime;
Expand All @@ -202,6 +206,13 @@ class MyRadio_User extends ServiceAPI implements APICaller
*/
private $contract_signed;

/**
* The user profile's end-of-life state.
*
* @var int
*/
private $eol_state;

/**
* Initiates the User variables.
*
Expand All @@ -215,7 +226,8 @@ protected function __construct($memberid)
'SELECT fname, sname, college AS collegeid, l_college.descr AS college,
phone, email, receive_email::boolean::text, local_name, local_alias, eduroam,
account_locked::boolean::text, last_login, joined, profile_photo, bio,
auth_provider, require_password_change::boolean::text, contract_signed::boolean::text
auth_provider, require_password_change::boolean::text, contract_signed::boolean::text,
eol_state
FROM member, l_college
WHERE memberid=$1
AND member.college = l_college.collegeid
Expand Down Expand Up @@ -669,6 +681,18 @@ public function getAccountLocked()
return $this->account_locked;
}

/**
* Returns this User account's end-of-life state.
*
* Use the MyRadio_User::EOL_STATE_* constants to compare, using >= if appropriate.
*
* @return int
*/
public function getEolState()
{
return $this->eol_state;
}

/**
* Get all the User's past, present and future officerships.
* @param bool $includeMemberships if true, non-officer team memberships will be included
Expand Down Expand Up @@ -707,7 +731,7 @@ public function getRadioTime()
if (!$this->radioTime) {
try{
$this->radioTime = self::$db->fetchColumn(
'SELECT sum(duration)
'SELECT sum(duration)
FROM schedule.show_season_timeslot
INNER JOIN schedule.show_season USING (show_season_id)
INNER JOIN schedule.show_credit USING (show_id)
Expand Down Expand Up @@ -870,15 +894,17 @@ public static function findByName($name, $limit = -1)
return self::$db->fetchAll(
'SELECT memberid, fname, sname, eduroam, local_alias FROM member
WHERE fname ILIKE $1 || \'%\' AND sname ILIKE $2 || \'%\'
AND eol_state < $4
ORDER BY sname, fname LIMIT $3',
[$names[0], $names[1], $limit]
[$names[0], $names[1], $limit, self::EOL_STATE_DEACTIVATED]
);
} else {
return self::$db->fetchAll(
'SELECT memberid, fname, sname, eduroam, local_alias FROM member
WHERE fname ILIKE $1 || \'%\' OR sname ILIKE $1 || \'%\'
AND eol_state < $3
ORDER BY sname, fname LIMIT $2',
[$name, $limit]
[$name, $limit, self::EOL_STATE_DEACTIVATED]
);
}
}
Expand Down Expand Up @@ -2052,6 +2078,93 @@ public function grantPermission($authid, $from = null, $to = null)
}
}

/**
* Deactivates this user (EOL Tier 1). They will not be able to sign in, receive email, receive credits for
* any shows, and any officerships will be ended.
*
* Note: DO NOT CALL THIS DIRECTLY outside of the relevant daemon! Instead use requestDeactivation, as it
markspolakovs marked this conversation as resolved.
Show resolved Hide resolved
* properly enqueues the request and sends a warning email.
*/
public function deactivate()
{
// Start a transaction.
self::$db->query('BEGIN');

// Update profile
self::$db->query('
UPDATE public.member
SET eol_state = $2,
receive_email = FALSE,
account_locked = TRUE
WHERE memberid = $1
', [
$this->getID(),
MyRadio_User::EOL_STATE_DEACTIVATED
]);

// End all officerships
self::$db->query('
UPDATE public.member_officer
SET till_date = NOW()
WHERE memberid = $1
AND till_date IS NULL
', [
$this->getID()
]);

// Unsub from all email
self::$db->query('
DELETE FROM public.mail_subscription
WHERE memberid = $1
AND (SELECT subscribable FROM public.mail_list WHERE mail_list.listid = mail_subscription.listid)
', [
$this->getID()
]);

// Don't forget!
self::$db->query('COMMIT');

// Sync up local changes
$this->eol_state = MyRadio_User::EOL_STATE_DEACTIVATED;
$this->receive_email = false;
$this->account_locked = true;

// Yeet the entire cache
self::$cache->purge();

// And send a goodbye email
// We use mail() manually to avoid hacking with the innards of MyRadioEmail
// (as it'd refuse to send due to receive_email being false)
// TODO: is this a good idea?
$domain = Config::$email_domain;
$long_name = Config::$long_name;
$short_name = Config::$short_name;
mail(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There must be an existing send mail function somewhere

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment immediately above:

We use mail() manually to avoid hacking with the innards of MyRadioEmail (as it'd refuse to send due to receive_email being false)

You do have a valid point though, and it may be better to refactor MRE to allow "send immediately, even if they've opted out".

$this->getName() . ' <' . $this->getEmail() . '>',
'MyRadio Account Deactivated',
utf8_encode(<<<EMAIL
Hello,

As requested, your MyRadio account has been deactivated. You can no longer sign in, and you will not receive any email after this.

If you ever wish to re-activate your account, please email computing@$domain.

If you did not request the deactivation of your account, please contact us immediately at computing@$domain.

Thank you for all your contributions to $long_name.

Yours sincerely,
$short_name Computing Team
EMAIL
),
implode('\r\n', [
'From: '.Config::$long_name.' <no-reply@'.Config::$email_domain.'>',
'Return-Path: no-reply@'.Config::$email_domain,
'Content-Type: text/plain; charset=utf-8'
])
);
}

/**
* Generates the form needed to quick-add URY members.
*
Expand Down