Files
ops-Gazelle/classes/applicant.class.php
T
itismadness d6d0d5fff6 Add invites to BP store, add purchase log, no longer give invites via schedule
Squashed commit of the following:

Author: Spine <[email protected]>

    schema additions for bonus points
    we do not hand out invitations any more
    move Bonus code from classes/ to app/
    BP items are now stored in the database, purchase history is recorded, add invites as an item to purchase
    Fix some stupid bugs
    switch reversed title labels

Author: itismadness <[email protected]>

    Fix coding standards and some slight bugs
    Fix join I broke by renaming SQL columns
    Remove double charge on purchasing titles
    Update user page to properly reflect capitalization change in arrays
    Check that user meets MinClass for purchasing invites
    change price for invite to 20,000 BP
2018-03-09 00:30:25 -05:00

325 lines
10 KiB
PHP

<?php
class Applicant {
private $id;
private $role_id;
private $user_id;
private $thread;
private $resolved;
private $created;
private $modified;
const CACHE_KEY = 'applicant_%d';
const CACHE_KEY_OPEN = 'applicant_list_open_%d';
const CACHE_KEY_RESOLVED = 'applicant_list_resolved_%d';
const CACHE_KEY_NEW_COUNT = 'applicant_new_count';
const CACHE_KEY_NEW_REPLY = 'applicant_new_reply';
const ENTRIES_PER_PAGE = 1000; // TODO: change to 50 and implement pagination
/**
* persistent Applicant constructor
* @param int $user_id id of applicant in users_main table
* @param string $role The name of the role the applicant is applying for
* @param string $body Their application request
*/
public function __construct ($user_id = null, $role = null, $body = null) {
if (!isset($user_id)) {
return;
}
$this->user_id = $user_id;
$this->thread = new Thread('staff-role');
$this->role_id = ApplicantRole::get_id($role);
$this->body = $body;
$this->resovled = false;
G::$DB->prepared_query("
INSERT INTO applicant (RoleID, UserID, ThreadID, Body)
VALUES (?, ?, ?, ?)
", $this->role_id, $this->user_id, $this->thread->id(), $this->body
);
$this->id = G::$DB->inserted_id();
G::$Cache->delete_value(self::CACHE_KEY_NEW_COUNT);
$this->flush_applicant_list_cache();
}
private function flush_applicant_list_cache() {
G::$Cache->delete_value('user_is_applicant.' . $this->user_id);
for ($page = 1; $page; ++$page) {
$hit = 0;
$cache_key = [
sprintf(self::CACHE_KEY_OPEN, $page),
sprintf(self::CACHE_KEY_RESOLVED, $page),
sprintf(self::CACHE_KEY_OPEN . ".$this->user_id", $page),
sprintf(self::CACHE_KEY_RESOLVED . ".$this->user_id", $page)
];
foreach ($cache_key as $key) {
if (G::$Cache->get_value($key) !== false) {
++$hit;
G::$Cache->delete_value($key);
}
}
if (!$hit) {
break;
}
}
return $this;
}
public function id() {
return $this->id;
}
public function user_id() {
return $this->user_id;
}
public function thread() {
return $this->thread;
}
public function thread_id() {
return $this->thread->id();
}
public function role_title() {
return ApplicantRole::get_title($this->role_id);
}
public function body() {
return $this->body;
}
public function created() {
return $this->created;
}
public function resolve($resolved = true) {
$this->resolved = $resolved;
G::$DB->prepared_query("
UPDATE applicant
SET Resolved = ?
WHERE ID = ?
", $this->resolved, $this->id);
$key = sprintf(self::CACHE_KEY, $this->id);
$data = G::$Cache->get_value($key);
if ($data !== false) {
$data['Resolved'] = $this->resolved;
G::$Cache->replace_value($key, $data, 86400);
}
G::$Cache->delete_value('user_is_applicant.' . $this->user_id);
return $this->flush_applicant_list_cache();
}
public function is_resolved() {
return $this->resolved;
}
// DELEGATES
/**
* Save the applicant thread note (see Thread class)
*/
public function save_note($poster_id, $body, $visibility) {
$this->thread->save_note($poster_id, $body, $visibility);
G::$Cache->delete_value(sprintf(self::CACHE_KEY, $this->id));
G::$Cache->delete_value(self::CACHE_KEY_NEW_REPLY);
G::$Cache->delete_value(self::CACHE_KEY_NEW_COUNT);
if ($visibility == 'public' && Permissions::has_permission($poster_id, 'admin_manage_applicants')) {
$staff = Users::user_info($poster_id);
$user = Users::user_info($this->user_id());
Misc::send_pm(
$this->user_id(),
0,
sprintf('You have a reply to your %s application', $this->role_title()),
sprintf(<<<END_MSG
Hello %s,
%s has replied to your application for the role of %s.
You can view the reply [url=%s]here[/url].
~APL STAFF <3
END_MSG
, $user['Username']
, $staff['Username']
, $this->role_title()
, site_url() . '/apply.php?action=view&id=' . $this->id()
)
);
}
return $this->flush_applicant_list_cache();
}
public function delete_note($note_id) {
G::$Cache->delete_value(self::CACHE_KEY_NEW_REPLY);
$this->thread()->delete_note($note_id);
return $this->flush_applicant_list_cache();
}
/**
* Get the applicant thread story (see Thread class)
*/
public function get_story() {
return $this->thread->get_story();
}
// FACTORY METHODS
/**
* Instantiate an instance of an Applicant from an id
* @param $id int The id of an Applicant
* @return an Applicant object
*/
static public function factory($id) {
$applicant = new self();
$key = sprintf(self::CACHE_KEY, $id);
$data = G::$Cache->get_value($key);
if ($data === false) {
G::$DB->prepared_query("
SELECT a.RoleID, a.UserID, a.ThreadID, a.Body, a.Resolved, a.Created, a.Modified
FROM applicant a
WHERE a.ID = ?
", $id);
if (G::$DB->has_results()) {
$data = G::$DB->next_record();
G::$Cache->cache_value($key, $data, 86400);
}
}
$applicant->id = $id;
$applicant->role_id = $data['RoleID'];
$applicant->user_id = $data['UserID'];
$applicant->thread = Thread::factory($data['ThreadID']);
$applicant->body = $data['Body'];
$applicant->resolved = $data['Resolved'];
$applicant->created = $data['Created'];
$applicant->modified = $data['Modified'];
return $applicant;
}
/**
* Get an array of applicant entries (e.g. for an index/table of contents page).
* Each array element is a hash with the following keys:
* ID - the Applicant id (in the applicant table)
* RoleID - the role the applicant is applying for
* UserID - the id of the member making the application
* UserName - the name of the member making the application
* ThreadID - the thread story associated with this application
* Created - when this application was created
* Modified - when this application was last modified
* nr_notes - the number of notes (0 or more) in the story
* last_UserID - user ID of the most recent person to comment in the thread
* last_Username - username of the most recent person to comment in the thread
* last_Created - the timestamp of the most recent comment
* @param $page int The page number to fetch (50 entries) defaults to 1
* @param $resolved int Should resolved applications be included (defaults to no).
* @param $user_id int If non-zero, return applications of this user_id
* @return a list of Applicant information
*/
static public function get_list($page = 1, $resolved = false, $user_id = 0) {
$key = sprintf($resolved ? self::CACHE_KEY_RESOLVED : self::CACHE_KEY_OPEN, $page);
if ($user_id) {
$key .= ".$user_id";
}
$list = G::$Cache->get_value($key);
if ($list === false) {
$user_condition = $user_id ? 'a.UserID = ?' : '0 = ? /* manager */';
G::$DB->prepared_query($sql = <<<END_SQL
SELECT APP.ID, r.Title as Role, APP.UserID, u.Username, APP.Created, APP.Modified, APP.nr_notes,
last.UserID as last_UserID, ulast.Username as last_Username, last.Created as last_Created
FROM
(
SELECT a.ID as ID, a.RoleID, a.UserID, a.ThreadID, a.Created, a.Modified,
count(n.ID) as nr_notes, max(n.ID) as last_noteid
FROM applicant a
LEFT JOIN thread_note n using (ThreadID)
WHERE a.Resolved = ?
AND $user_condition
GROUP BY a.ID, a.RoleID, a.UserID, a.ThreadID, a.Created, a.Modified
) APP
INNER JOIN applicant_role r ON (r.ID = APP.RoleID)
INNER JOIN users_main u ON (u.ID = APP.UserID)
LEFT JOIN thread_note last USING (ThreadID)
LEFT JOIN users_main ulast ON (ulast.ID = last.UserID)
WHERE (last.ID IS NULL or last.ID = APP.last_noteid)
ORDER by r.Modified DESC,
GREATEST(coalesce(last.Created, '1970-01-01 00:00:00'), APP.Created) DESC
LIMIT ? OFFSET ?
END_SQL
, $resolved ? 1 : 0, $user_id, self::ENTRIES_PER_PAGE, ($page-1) * self::ENTRIES_PER_PAGE);
$list = G::$DB->has_results() ? G::$DB->to_array() : [];
G::$Cache->cache_value($key, $list, 86400);
}
return $list;
}
public static function user_is_applicant($user_id) {
$key = 'user_is_applicant.' . $user_id;
$has_application = G::$Cache->get_value($key);
if ($has_application === false) {
$has_application = -1;
G::$DB->prepared_query('SELECT 1 FROM applicant WHERE UserID = ? LIMIT 1', $user_id);
if (G::$DB->has_results()) {
$data = G::$DB->next_record();
if ($data[0] == 1) {
$has_application = 1;
}
}
G::$Cache->cache_value($key, $has_application, 86400);
}
return $has_application > 0;
}
public static function new_applicant_count() {
$key = self::CACHE_KEY_NEW_COUNT;
$applicant_count = G::$Cache->get_value($key);
if ($applicant_count === false) {
G::$DB->prepared_query("
SELECT count(a.ID) as nr
FROM applicant a
INNER JOIN thread t ON (a.ThreadID = t.ID
AND t.ThreadTypeID = (SELECT ID FROM thread_type WHERE Name = ?)
)
LEFT JOIN thread_note n ON (n.threadid = t.id)
WHERE a.Resolved = 0
AND n.id IS NULL
", 'staff-role'
);
if (G::$DB->has_results()) {
$data = G::$DB->next_record();
$applicant_count = $data['nr'];
}
G::$Cache->cache_value($key, $applicant_count, 3600);
}
return $applicant_count;
}
public static function new_reply_count() {
$key = self::CACHE_KEY_NEW_REPLY;
$reply_count = G::$Cache->get_value($key);
if ($reply_count === false) {
G::$DB->prepared_query("
SELECT count(*) AS nr
FROM applicant a
INNER JOIN thread_note n USING (ThreadID)
INNER JOIN (
/* find the last person to comment in an applicant thread */
SELECT a.ID, max(n.ID) AS noteid
FROM applicant a
INNER JOIN thread t ON (a.threadid = t.id
AND t.ThreadTypeID = (SELECT ID FROM thread_type WHERE Name = ?)
)
INNER JOIN thread_note n ON (n.ThreadID = a.ThreadID)
WHERE a.Resolved = 0
GROUP BY a.ID
) X ON (n.ID = X.noteid)
WHERE a.UserID = n.UserID /* if they are the applicant: not a staff response Q.E.D. */
", 'staff-role'
);
if (G::$DB->has_results()) {
$data = G::$DB->next_record();
$reply_count = $data['nr'];
}
G::$Cache->cache_value($key, $reply_count, 3600);
}
return $reply_count;
}
}