public static function load($name, $options = array())
 {
     $db = Settings::getProtected('db');
     $auth = Settings::getProtected('auth');
     $auth->forceAuthentication();
     $username = $auth->getUsername();
     if (array_key_exists('include-removed', $options) && $options['include-removed'] == true) {
         $includeRemoved = true;
     } else {
         $includeRemoved = false;
     }
     $items = array();
     $results = $db->loadQueue($name, $includeRemoved);
     if (strpos($name, 'proof') != false) {
         $type = 'proof';
     } else {
         if (strpos($name, 'review') != false) {
             $type = 'review';
         }
     }
     foreach ($results as $result) {
         $itemID = $result['item_id'];
         $projectID = $result['project_id'];
         $item = new Item($db);
         $item->loadWithProjectID($itemID, $projectID, $username, $type);
         array_push($items, $item);
     }
     return $items;
 }
Example #2
0
 public function Item($itemId = '', $projectSlug = '', $username = '', $type = 'proof')
 {
     $this->db = Settings::getProtected('db');
     if ($itemId && $projectSlug) {
         $this->load($itemId, $projectSlug, $username, $type);
     }
 }
Example #3
0
 public static function sendMessage($to, $subject, $message)
 {
     $admin_email = Settings::getProtected('admin_email');
     $headers = "From: {$admin_email}" . "\r\n";
     $headers .= "Reply-To: {$admin_email}" . "\r\n";
     $headers .= "X-Mailer: PHP/" . phpversion();
     return mail($to, $subject, $message, $headers);
 }
 public static function forceClearance($roles, $user, $params = array(), $error = 'error.insufficient_rights')
 {
     $app_url = Settings::getProtected('app_url');
     $i18n = new I18n("../translations", Settings::getProtected('language'));
     if (!self::verify($roles, $user, $params)) {
         Utils::redirectToDashboard('', $i18n->t($error));
         return false;
     }
     return true;
 }
 public function ItemTypeUploader($projectSlug)
 {
     $this->itemData = array();
     $this->items = array();
     $this->files = array();
     $this->projectSlug = $projectSlug;
     $sysPath = Settings::getProtected('sys_path');
     $this->tempDir = "{$sysPath}/htdocs/media/temp/{$this->projectSlug}";
     $project = new Project($projectSlug);
     $this->projectId = $project->project_id;
 }
Example #6
0
 public static function redirectToDashboard($message, $error)
 {
     $app_url = Settings::getProtected('app_url');
     if ($message != '') {
         $_SESSION['ub_message'] = trim($message);
     }
     if ($error != '') {
         $_SESSION['ub_error'] = trim($error);
     }
     header("Location: {$app_url}");
 }
 public static function load($params)
 {
     $item = $params['item'];
     $type = $params['type'];
     $auth = Settings::getProtected('auth');
     $auth->forceAuthentication();
     $username = $auth->getUsername();
     $user = new User($username);
     // Make sure user has access (member of project, item is in queue)
     // TODO: Finish
     return $user->loadTranscript($item, $type);
 }
 public static function admin($params)
 {
     $format = Utils::getFormat($params['args'], 0, 2);
     $app_url = Settings::getProtected('app_url');
     $db = Settings::getProtected('db');
     $user = User::getAuthenticatedUser();
     // Make sure the user is at least creator or admin
     RoleController::forceClearance(array('system.creator', 'system.admin'), $user);
     // Get latest work for the user's projects
     $latestWorkList = $db->getAdminProjectsLatestWork($user->username, 5);
     $latestWork = array();
     foreach ($latestWorkList as $work) {
         $qn = $work['queue_name'];
         $type = substr($qn, strpos($qn, '.') + 1, strpos($qn, ':') - strpos($qn, '.') - 1);
         $username = substr($qn, strpos($qn, ':') + 1);
         $item = new Item($work['item_id'], $work['project_slug']);
         $project = new Project($work['project_slug']);
         if ($item->project_type == 'system') {
             $transcriptURL = "{$app_url}/projects/" . $item->project_slug . "/items/" . $item->item_id . "/{$type}/{$username}";
             $editURL = "{$app_url}/projects/" . $item->project_slug . "/items/" . $item->item_id . "/edit";
         } else {
             $transcriptURL = "{$app_url}/" . $item->project_owner . "/projects/" . $item->project_slug . "/items/" . $item->item_id . "/{$type}/{$username}";
             $editURL = "{$app_url}/" . $item->project_owner . "/projects/" . $item->project_slug . "/items/" . $item->item_id . "/edit";
         }
         array_push($latestWork, array('item' => $item->getResponse(), 'project' => $project->getResponse(), 'type' => $type, 'username' => $username, 'date_completed' => $work['date_completed'], 'transcript_url' => $transcriptURL, 'edit_url' => $editURL));
     }
     $newestMembers = $db->getNewestProjectMembers($user->username, 5);
     // Only get list of users if they're a site admin
     $users = array();
     if ($user->role == 'admin') {
         $usernameList = $db->getUsers();
         foreach ($usernameList as $username) {
             $tempUser = new User($username['username']);
             $tempUserArray = $tempUser->getResponse();
             // Get list of projects they're working on
             $projects = $db->getUserProjectsWithStats($username['username']);
             $tempUserArray['projects'] = $projects;
             array_push($users, $tempUserArray);
         }
     }
     $response = array('page_title' => 'Admin Dashboard', 'user' => $user->getResponse(), 'latest_work' => $latestWork, 'newest_members' => $newestMembers, 'users' => $users);
     switch ($format) {
         case 'json':
             echo json_encode($response);
             break;
         case 'html':
             Template::render('admin_dashboard', $response);
             break;
     }
 }
Example #9
0
 public static function render($page, $options, $theme = 'core')
 {
     $cached = Settings::getProtected('theme_cached');
     // If there's a system-wide theme in config.yaml, use it as the default instead
     $settingsTheme = Settings::getProtected('theme');
     if ($settingsTheme != 'core' && $theme == 'core') {
         $theme = $settingsTheme;
     }
     if ($cached) {
         $twig_opts = array('cache' => '../templates/cache');
     } else {
         $twig_opts = array();
     }
     $loader = new Twig_Loader_Filesystem(array("../templates/{$theme}", "../templates/core"));
     $twig = new Twig_Environment($loader, $twig_opts);
     $options['title'] = Settings::getProtected('title');
     $options['app_url'] = Settings::getProtected('app_url');
     $options['google_analytics'] = Settings::getProtected('google_analytics');
     $options['theme_root'] = $options['app_url'] . "/themes/{$theme}";
     $options['i18n'] = new I18n("../translations", Settings::getProtected('language'));
     $options['message'] = Utils::SESSION('ub_message');
     $options['error'] = Utils::SESSION('ub_error');
     $auth = Settings::getProtected('auth');
     if ($auth->authenticated()) {
         $username = $auth->getUsername();
         if (isset($username)) {
             $options['username'] = $auth->getUsername();
         }
     }
     // Prepare the methods they want
     if (array_key_exists('registered_methods', $options)) {
         // TODO: get user token
         $userToken = 'foo';
         $appName = 'unbindery';
         $privateKey = Settings::getProtected('private_key');
         $devKeys = Settings::getProtected('devkeys');
         $devKey = $devKeys['unbindery'];
         $options['methods'] = array();
         foreach ($options['registered_methods'] as $method) {
             // Create the signature hash for each method we'll use on the page in Javascript
             $options['methods'][$method] = array("name" => $method, "value" => md5($method . $userToken . $appName . $privateKey . $devKey));
         }
     }
     echo $twig->render("{$page}.html", $options);
     // Now that we've displayed it, get rid of it
     unset($_SESSION['ub_message']);
     unset($_SESSION['ub_error']);
 }
Example #10
0
 public function preprocess($filenames)
 {
     // Get settings
     $sysPath = Settings::getProtected('sys_path');
     $uploaders = Settings::getProtected('uploaders');
     $chunkSize = $uploaders['Audio']['chunksize'];
     $chunkOverlap = $uploaders['Audio']['chunkoverlap'];
     $ffmpegPath = $uploaders['Audio']['ffmpeg'];
     // Chunk each MP3 into smaller segments
     foreach ($filenames as $file) {
         $path = "{$this->tempDir}/{$file}";
         // These four lines from http://stackoverflow.com/questions/3069574/get-the-length-of-an-audio-file-php
         $execStr = $ffmpegPath . " -i {$path} 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//";
         $time = exec($execStr);
         list($hms, $milli) = explode('.', $time);
         list($hours, $minutes, $seconds) = explode(':', $hms);
         $totalSeconds = $hours * 3600 + $minutes * 60 + $seconds;
         $count = 1;
         // If the MP3 is longer than the chunk size, split it
         if ($totalSeconds > $chunkSize) {
             $start = 0;
             // Get the filename and extension
             $filename = pathinfo($file, PATHINFO_FILENAME);
             $ext = pathinfo($file, PATHINFO_EXTENSION);
             // Get the size of the chunks, including the overlap
             $chunkSeconds = $chunkSize + $chunkOverlap;
             for ($start = 0; $start < $totalSeconds; $start += $chunkSize) {
                 // Prep output filename
                 $outputFilename = sprintf("{$filename}-%03d.{$ext}", $count);
                 $outputPath = "{$this->tempDir}/{$outputFilename}";
                 // And chunk the file
                 $execStr = $ffmpegPath . " -ss {$start} -i {$path} -t {$chunkSeconds} -acodec copy {$outputPath}";
                 exec($execStr);
                 // Add to files array
                 array_push($this->files, $outputFilename);
                 $count++;
             }
         }
     }
     // And create the item info array
     foreach ($this->files as $file) {
         // Strip off the extension for the title
         $title = pathinfo($file, PATHINFO_FILENAME);
         $item = array("title" => $title, "project_id" => $this->projectId, "transcript" => "", "type" => "audio", "href" => $file);
         array_push($this->itemData, $item);
     }
 }
 public static function parse($item, $action)
 {
     $auth = Settings::getProtected('auth');
     $auth->forceAuthentication();
     $username = $auth->getUsername();
     $user = new User($username);
     // Parse the action
     switch (trim($action)) {
         case '@proofer':
             $destinationQueue = "project.proof:" . $item->project_slug;
             break;
         case '@reviewer':
             $destinationQueue = "project.review:" . $item->project_slug;
             break;
         default:
             // username (defaults to proof, TODO: allow review as well)
             $destinationQueue = "user.proof:" . $action;
             break;
     }
     $queue = new Queue($destinationQueue);
     $queue->add($item);
     $queue->save();
 }
Example #12
0
 public function createAccount($user)
 {
     $app_url = Settings::getProtected('app_url');
     $email_subject = Settings::getProtected('email_subject');
     $admin_email = Settings::getProtected('admin_email');
     $i18n = new I18n("../translations", Settings::getProtected('language'));
     // Add username/email here if they're not already in Unbindery (unnecessary for Alibaba)
     // Example:
     // $user->username = $this->getUsername();
     // $user->email = $this->getEmail();
     // Generate hash
     $user->hash = md5($user->email . $user->username . time());
     // Add user to the database or update if they're already there
     $user->save();
     // Send confirmation link to user via email
     $message = $i18n->t('signup.confirmation_email', array("url" => "{$app_url}/signup/activate/{$user->hash}"));
     $status = Mail::sendMessage($user->email, "{$email_subject} " . $i18n->t('signup.confirmation_link'), $message);
     if ($status == 1) {
         $status = "done";
     } else {
         $status = "error mailing";
     }
     $status = Mail::sendMessage($admin_email, "{$email_subject} " . $i18n->t('signup.new_signup'), $i18n->t('signup.new_user') . " {$user->username} <{$user->email}>");
 }
 public static function sendNotification($to, $notification, $params)
 {
     $i18n = new I18n("../translations", Settings::getProtected('language'));
     error_log("Sending {$notification}.subject / {$notification}.message");
     $subject = self::replaceVariables($i18n->t("{$notification}.subject"), $params);
     $email_subject = Settings::getProtected('email_subject');
     if ($email_subject) {
         $subject = "{$email_subject} {$subject}";
     }
     $message = self::replaceVariables($i18n->t("{$notification}.message"), $params);
     Mail::sendMessage($to, $subject, $message);
 }
Example #14
0
 public static function getAuthenticatedUser()
 {
     $auth = Settings::getProtected('auth');
     $auth->forceAuthentication();
     return new User($auth->getUsername());
 }
Example #15
0
 public static function removeFileForItem($item)
 {
     $sysPath = Settings::getProtected('sys_path');
     // Load the project
     $project = new Project($item->project_slug);
     // Set up the target dir
     if ($project->type == 'system') {
         $projectDir = "{$sysPath}/htdocs/media/projects/{$project->slug}";
     } else {
         if ($project->type == 'user') {
             $projectDir = "{$sysPath}/htdocs/media/users/{$project->owner}/{$project->slug}";
         }
     }
     // File path
     $filePath = "{$projectDir}/{$item->href}";
     // Remove the file
     if ($projectDir != '' && file_exists($filePath)) {
         return unlink($filePath);
     }
     return false;
 }
Example #16
0
 public static function getPublicCompletedProjects($user = '', $limit = true)
 {
     $app_url = Settings::getProtected('app_url');
     $db = Settings::getProtected('db');
     $projects = $db->getPublicCompletedProjects($user, $limit);
     foreach ($projects as &$project) {
         $project["title"] = stripslashes($project["title"]);
         if ($project["type"] == "system") {
             $project["link"] = "{$app_url}/projects/{$project["slug"]}";
         } else {
             if ($project["type"] == "user") {
                 $project["link"] = "{$app_url}/users/{$project["owner"]}/projects/{$project["slug"]}";
             }
         }
     }
     return $projects;
 }
 public static function import($params)
 {
     $appUrl = Settings::getProtected('app_url');
     $themeRoot = Settings::getProtected('theme_root');
     $format = Utils::getFormat($params['args'], 1, 3);
     $projectType = Utils::getProjectType($params['args']);
     $projectSlug = $projectType == 'system' ? $params['args'][0] : $params['args'][2];
     $user = User::getAuthenticatedUser();
     // Load the project
     $project = new Project($projectSlug);
     RoleController::forceClearance(array('project.admin', 'project.owner', 'system.admin'), $user, array('project' => $project));
     if ($project->title == '') {
         Utils::redirectToDashboard('', 'Error loading project.');
     }
     if ($project->type == 'system') {
         $projectUrl = "projects/" . $project->slug;
     } else {
         if ($project->type == 'user') {
             $projectUrl = "users/" . $project->owner . "/projects/" . $project->slug;
         }
     }
     $project->getItems();
     $projectArray = $project->getResponse();
     $projectArray['items'] = $project->items;
     $projectArray['url'] = "{$appUrl}/{$projectUrl}";
     switch ($params['method']) {
         // GET: Get transcript import page
         case 'GET':
             $response = array('page_title' => 'Import Transcript', 'user' => $user->getResponse(), 'project' => $projectArray);
             switch ($format) {
                 case 'json':
                     echo json_encode(array('status' => 'success', 'response' => $response));
                     break;
                 case 'html':
                     Template::render('import', $response);
                     break;
             }
             break;
             // POST: Update transcripts for items
         // POST: Update transcripts for items
         case 'POST':
             $template = Utils::POST('template');
             $transcript = Utils::POST('transcript');
             $items = Utils::POST('items');
             $projectSlug = Utils::POST('projectSlug');
             $status = 'success';
             // Split the transcript
             $splitTranscripts = TranscriptController::splitTranscript($transcript, $template);
             // Make sure the number of items still matches, otherwise return error
             if (count($splitTranscripts) != count($items)) {
                 $status = 'error';
             }
             // Update each item's transcript
             for ($i = 0; $i < count($items); $i++) {
                 $item = new Item($items[$i], $projectSlug);
                 $item->transcript = $splitTranscripts[$i];
                 if (!$item->save()) {
                     $status = 'error';
                     break;
                 }
             }
             echo json_encode(array('status' => $status));
             break;
     }
 }
Example #18
0
// Initialize event manager
// --------------------------------------------------
$eventManager = new EventManager();
Settings::setProtected('eventManager', $eventManager);
// Initialize transcript controller
// --------------------------------------------------
Transcript::setEventManager($eventManager);
Transcript::register('load', array('TranscriptController', 'load'));
Transcript::register('save', array('TranscriptController', 'save'));
Transcript::register('diff', array('TranscriptController', 'diff'));
// Initialize workflow controller
// --------------------------------------------------
Workflow::register('callback', array('WorkflowController', 'parse'));
// Initialize notifications controller
// --------------------------------------------------
$notifications = Settings::getProtected('notifications');
$notificationsList = array();
foreach ($notifications as $key => $value) {
    // Get an array of just the keys
    array_push($notificationsList, $key);
}
$notify = new NotificationManager();
$notify->setEventManager($eventManager);
$notify->registerNotifications($notificationsList, array('NotificationController', 'send'));
Settings::setProtected('notify', $notify);
// Parse the routes
// --------------------------------------------------
// The \.?([^/]*)?/? at the end allows us to add .json, etc. for other formats
// Create the routes we want to use
$routes = array('#^/?$#' => 'SystemPageController::index', '#^/login/?$#' => 'SystemPageController::login', '#^/logout/?$#' => 'SystemPageController::logout', '#^/signup(\\.[^/]+)?/?$#' => 'SystemPageController::signup', '#^/signup/activate/(.*)(\\.[^/]+)?/?$#' => 'SystemPageController::activate', '#^/messages/?$#' => 'SystemPageController::message', '#^/install/?$#' => 'SystemPageController::install', '#^/test/(.*)/?$#' => 'SystemPageController::test', '#^/(users)/([^/]+)/projects/([^/]+)/items/get(\\.[^/]+)?/?#' => 'ItemPageController::getNewItem', '#^/(users)/([^/]+)/projects/([^/]+)/items/([^/.]+)/transcript(\\.[^/]+)?/?#' => 'ItemPageController::transcript', '#^/(users)/([^/]+)/projects/([^/]+)/items/([^/.]+)/delete(\\.[^/]+)?/?#' => 'ItemPageController::deleteItem', '#^/(users)/([^/]+)/projects/([^/]+)/items/([^/.]+)/(proof|review)(\\.[^/]+)?/?#' => 'ItemPageController::itemProof', '#^/(users)/([^/]+)/projects/([^/]+)/items/([^/.]+)/(proof|review|edit)(\\.[^/]+)?/?#' => 'ItemPageController::itemProof', '#^/(users)/([^/]+)/projects/([^/]+)/items/([^/.]+)(\\.[^/]+)?/?#' => 'ItemPageController::item', '#^/(users)/([^/]+)/projects/([^/]+)/items(\\.[^/]+)?/?#' => 'ItemPageController::items', '#^/(users)/([^/]+)/projects/([^/]+)/transcript/split(\\.[^/]+)?/?#' => 'ProjectPageController::splitTranscript', '#^/(users)/([^/]+)/projects/([^/]+)/transcript(\\.[^/]+)?/?#' => 'ProjectPageController::transcript', '#^/(users)/([^/]+)/projects/([^/]+)/membership/leave(\\.[^/]+)?/?#' => 'ProjectPageController::membershipLeave', '#^/(users)/([^/]+)/projects/([^/]+)/membership(\\.[^/]+)?/?#' => 'ProjectPageController::membership', '#^/(users)/([^/]+)/projects/([^/]+)/admin(\\.[^/]+)?/?#' => 'ProjectPageController::admin', '#^/(users)/([^/]+)/projects/([^/]+)/upload(\\.[^/]+)?/?#' => 'ProjectPageController::upload', '#^/(users)/([^/]+)/projects/([^/]+)/import(\\.[^/]+)?/?#' => 'ProjectPageController::import', '#^/(users)/([^/]+)/projects/new-project(\\.[^/]+)?/?#' => 'ProjectPageController::newProject', '#^/(users)/([^/]+)/projects/([^/.]+)(\\.[^/]+)?/?#' => 'ProjectPageController::projectPage', '#^/(users)/([^/]+)/projects(\\.[^/]+)?/?#' => 'ProjectPageController::projects', '#^/users/([^/]+)/dashboard(\\.[^/]+)?/?#' => 'UserPageController::userDashboard', '#^/users/([^/]+)/settings(\\.[^/]+)?/?#' => 'UserPageController::userSettings', '#^/users/([^/.]+)(\\.[^/]+)?/?#' => 'UserPageController::userPage', '#^/users(\\.[^/]+)?/?#' => 'UserPageController::users', '#^/projects/([^/]+)/items/get(\\.[^/]+)?/?#' => 'ItemPageController::getNewItem', '#^/projects/([^/]+)/items/([^/.]+)/transcript(\\.[^/]+)?/?#' => 'ItemPageController::transcript', '#^/projects/([^/]+)/items/([^/.]+)/delete(\\.[^/]+)?/?#' => 'ItemPageController::deleteItem', '#^/projects/([^/]+)/items/([^/.]+)/(proof|review)/(\\.[^/]+)/?#' => 'ItemPageController::itemProof', '#^/projects/([^/]+)/items/([^/.]+)/(proof|review|edit)(\\.[^/]+)?/?#' => 'ItemPageController::itemProof', '#^/projects/([^/]+)/items/([^/.]+)(\\.[^/]+)?/?#' => 'ItemPageController::item', '#^/projects/([^/]+)/items(\\.[^/]+)?/?#' => 'ItemPageController::items', '#^/projects/([^/]+)/transcript/split(\\.[^/]+)?/?#' => 'ProjectPageController::splitTranscript', '#^/projects/([^/]+)/transcript(\\.[^/]+)?/?#' => 'ProjectPageController::transcript', '#^/projects/([^/]+)/membership/leave(\\.[^/]+)?/?#' => 'ProjectPageController::membershipLeave', '#^/projects/([^/]+)/membership(\\.[^/]+)?/?#' => 'ProjectPageController::membership', '#^/projects/([^/]+)/admin(\\.[^/]+)?/?#' => 'ProjectPageController::admin', '#^/projects/([^/]+)/upload(\\.[^/]+)?/?#' => 'ProjectPageController::upload', '#^/projects/([^/]+)/import(\\.[^/]+)?/?#' => 'ProjectPageController::import', '#^/projects/new-project(\\.[^/]+)?/?#' => 'ProjectPageController::newProject', '#^/projects/([^/.]+)(\\.[^/]+)?/?#' => 'ProjectPageController::projectPage', '#^/projects(\\.[^/]+)?/?#' => 'ProjectPageController::projects', '#^/admin(\\.[^/]+)?/?$#' => 'AdminPageController::admin');
$router = new Router('SystemPageController::fileNotFound');
 public static function install($params)
 {
     // Load database
     $db = Settings::getProtected('db');
     $installed = $db->installed();
     // Make sure we haven't already installed
     if ($installed) {
         // Already installed
         Utils::redirectToDashboard('error.already_installed', '');
     } else {
         // We haven't, so install
         switch ($params['method']) {
             // GET: Show install form
             case 'GET':
                 Template::render('install', array('external_login' => Settings::getProtected('external_login')));
                 break;
                 // POST: Run install script
             // POST: Run install script
             case 'POST':
                 // And install
                 if ($db->install()) {
                     // Sleep two seconds to make sure the tables are all created
                     sleep(2);
                     // Add admin user
                     $user = new User();
                     $user->username = Utils::POST('username');
                     if (Utils::POST('password')) {
                         $user->password = md5(Utils::POST('password'));
                         // TODO: make this better
                     } else {
                         $user->password = '';
                     }
                     $user->role = "admin";
                     $user->status = "active";
                     $user->hash = "adminadminadmin";
                     // doesn't really matter since we don't need to confirm
                     $user->in_db = false;
                     $user->save();
                     // Redirect to admin login page
                     $auth = Settings::getProtected('auth');
                     $auth->redirectToLogin();
                 } else {
                     Template::render('install', array('status' => 'failed'));
                 }
                 break;
         }
     }
 }
 public static function items($params)
 {
     $format = Utils::getFormat($params['args'], 0, 2);
     $projectType = Utils::getProjectType($params['args']);
     $projectSlugIndex = $projectType == 'system' ? 0 : 2;
     $projectSlug = $params['args'][$projectSlugIndex];
     switch ($params['method']) {
         // POST: Run uploaded files through item type uploader modules
         case 'POST':
             $fileList = Utils::POST('fileList');
             $items = array();
             foreach ($fileList as $file) {
                 // Get extension
                 $ext = pathinfo($file, PATHINFO_EXTENSION);
                 // Default uploader type
                 $uploaderType = "Page";
                 // Get the uploader type from the settings
                 $uploaders = Settings::getProtected('uploaders');
                 foreach ($uploaders as $type => $data) {
                     if (in_array($ext, $data['extensions'])) {
                         $uploaderType = $type;
                         break;
                     }
                 }
                 // Load the appropriate class
                 require_once "../modules/uploaders/{$uploaderType}Uploader.class.php";
                 $uploaderClass = "{$uploaderType}Uploader";
                 $uploader = new $uploaderClass($projectSlug);
                 // Call the uploader (it takes an array)
                 $returnedItems = $uploader->upload(array($file));
                 // Merge the arrays
                 $items = array_merge($items, $returnedItems);
             }
             // Create a JSON-ready version
             $finalItems = array();
             foreach ($items as $item) {
                 $newItem = array("id" => $item->item_id, "title" => $item->title, "project_id" => $item->project_id, "transcript" => $item->transcript, "type" => $item->type, "href" => $item->href);
                 array_push($finalItems, $newItem);
             }
             $uploader = new ItemTypeUploader($projectSlug);
             $uploader->cleanup();
             echo json_encode(array('status' => 'success', 'items' => $finalItems));
             break;
     }
 }
 public static function userDashboard($params)
 {
     $format = $params['args'][1] != '' ? $params['args'][1] : 'html';
     $app_url = Settings::getProtected('app_url');
     $user = User::getAuthenticatedUser();
     // Put it in the settings cache
     Settings::setProtected('username', $user->username);
     // Set up proofing and reviewing objects
     $proofing = array();
     $reviewing = array();
     // Load the user's proofing queue
     $proofQueue = new Queue("user.proof:{$user->username}");
     $proofing['items'] = array();
     foreach ($proofQueue->getItems() as $item) {
         array_push($proofing['items'], array('title' => $item->title, 'status' => $item->status, 'project_slug' => $item->project_slug, 'project_type' => $item->project_type, 'project_owner' => $item->project_owner, 'item_id' => $item->item_id, 'type' => $item->type));
     }
     // Load the user's reviewing queue
     $reviewQueue = new Queue("user.review:{$user->username}");
     $reviewing['items'] = array();
     foreach ($reviewQueue->getItems() as $item) {
         array_push($reviewing['items'], array('title' => $item->title, 'status' => $item->status, 'project_slug' => $item->project_slug, 'project_type' => $item->project_type, 'project_owner' => $item->project_owner, 'item_id' => $item->item_id, 'type' => $item->type));
     }
     // Add extra info (edit link and slug) to each item
     $prooflist = array();
     foreach ($proofing['items'] as &$item) {
         if ($item['project_type'] == 'system') {
             $item['editlink'] = $app_url . '/projects/' . $item['project_slug'] . '/items/' . $item['item_id'] . '/proof';
         } else {
             if ($item['project_type'] == 'user') {
                 $item['editlink'] = $app_url . '/users/' . $item['project_owner'] . '/projects/' . $item['project_slug'] . '/items/' . $item['item_id'] . '/proof';
             }
         }
         if (!in_array($item['project_slug'], $prooflist)) {
             $prooflist[] = $item['project_slug'];
         }
     }
     $reviewlist = array();
     foreach ($reviewing['items'] as &$item) {
         if ($item['project_type'] == 'system') {
             $item['editlink'] = $app_url . '/projects/' . $item['project_slug'] . '/items/' . $item['item_id'] . '/review';
         } else {
             if ($item['project_type'] == 'user') {
                 $item['editlink'] = $app_url . '/users/' . $item['project_owner'] . '/projects/' . $item['project_slug'] . '/items/' . $item['item_id'] . '/review';
             }
         }
         if (!in_array($item['project_slug'], $reviewlist)) {
             $reviewlist[] = $item["project_slug"];
         }
     }
     // Add link and percentages to each project
     $projects = $user->getProjectSummaries();
     $projectInfo = array();
     $proofing['projects'] = array();
     $reviewing['projects'] = array();
     foreach ($projects as &$project) {
         $roles = $user->getRolesForProject($project['slug']);
         // If the project is available for proofing or reviewing (with no items already claimed),
         // then add it to the appropriate list
         if (!in_array($project["slug"], $prooflist) && $project["available_to_proof"] > 0 && in_array('proofer', $roles)) {
             array_push($proofing['projects'], $project['slug']);
         }
         if (!in_array($project["slug"], $reviewlist) && $project["available_to_review"] > 0 && in_array('reviewer', $roles)) {
             array_push($reviewing['projects'], $project['slug']);
         }
         // Set up percentage bars
         if ($project['num_items'] == 0) {
             $project['percent_proofed'] = 0;
             $project['percent_reviewed'] = 0;
         } else {
             $project['percent_proofed'] = round($project['num_proofed'] / $project['num_items'] * 100, 0);
             $project['percent_reviewed'] = round($project['num_reviewed'] / $project['num_items'] * 100, 0);
         }
         // And the project link
         if ($project['type'] == 'system') {
             $project['link'] = $app_url . '/projects/' . $project['slug'];
         } else {
             if ($project['type'] == 'user') {
                 $project['link'] = $app_url . '/users/' . $project['owner'] . '/projects/' . $project['slug'];
             }
         }
         $projectInfo[$project['slug']] = $project;
     }
     // Blank slate condition if there are no items and no projects
     $proofing['blankslate'] = count($proofing['items']) == 0 && count($proofing['projects']) == 0 ? true : false;
     $reviewing['blankslate'] = count($reviewing['items']) == 0 && count($reviewing['projects']) == 0 ? true : false;
     // Get the user's history and the top proofers information
     $history = $user->getHistory();
     $topusers = User::getTopUsers();
     // Prepare user history
     foreach ($history as &$event) {
         if ($event['project_type'] == 'system') {
             $event['editlink'] = "{$app_url}/projects/" . $event['project_slug'] . '/items/' . $event['item_id'] . '/proof';
         } else {
             if ($project['type'] == 'user') {
                 $event['editlink'] = "{$app_url}/users/" . $event['project_owner'] . '/projects/' . $event['project_slug'] . '/items/' . $event['item_id'] . '/proof';
             }
         }
         $event['title'] = $event['item_title'];
     }
     $response = array('page_title' => 'Dashboard', 'user' => $user->getResponse(), 'projects' => $projectInfo, 'proofing' => array('items' => $proofing['items'], 'projects' => $proofing['projects'], 'blankslate' => $proofing['blankslate']), 'reviewing' => array('items' => $reviewing['items'], 'projects' => $reviewing['projects'], 'blankslate' => $reviewing['blankslate']), 'history' => $history, 'history_count' => count($history), 'registered_methods' => array('/users/' . $user->username), 'topusers' => $topusers);
     switch ($params['method']) {
         // GET: Get user dashboard
         case 'GET':
             switch ($format) {
                 case 'json':
                     echo json_encode($response);
                     break;
                 case 'html':
                     Template::render('dashboard', $response);
                     break;
             }
             break;
     }
 }
 public static function getNextAvailableItem($params)
 {
     $username = $params['username'];
     $projectSlug = $params['projectSlug'];
     $type = $params['type'];
     $role = $type . "er";
     $success = false;
     $errorCode = '';
     $db = Settings::getProtected('db');
     $auth = Settings::getProtected('auth');
     // Make sure we're authenticated as the user we say we are
     $auth->forceAuthentication();
     $loggedInUsername = $auth->getUsername();
     if ($username != $loggedInUsername) {
         $code = "not-authenticated-as-correct-user";
     }
     // Load user
     $user = new User($username);
     // Does this user belong to the project?
     if (!$user->isMember($projectSlug, $role)) {
         $code = "not-a-member";
     }
     // Does this user already have an item from this project?
     if ($user->hasProjectItem($projectSlug)) {
         $code = "has-unfinished-item";
     }
     // Load the user's queue
     $userQueue = new Queue("user.{$type}:{$username}", false, array('include-removed' => true));
     $userQueueItems = $userQueue->getItems();
     // Load the project's queue
     $queue = new Queue("project.{$type}:{$projectSlug}");
     $queueItems = $queue->getItems();
     // Go through the project queue and get the first item the user hasn't yet done
     foreach ($queueItems as $item) {
         if (!in_array($item, $userQueueItems)) {
             $nextItem = $item;
             break;
         }
     }
     if (isset($nextItem) && $nextItem->item_id != -1) {
         // Concatenate proofed transcripts
         if ($type == 'review') {
             // Get proofed transcripts for the new item
             $transcripts = $db->loadItemTranscripts($nextItem->project_id, $nextItem->item_id, 'proof');
             // Only diff them if there's more than one
             if (count($transcripts) > 1) {
                 $transcriptText = Transcript::diff($transcripts);
             } else {
                 $transcriptText = $transcripts[0]['transcript'];
             }
             // Only get the fields for the first transcript
             $transcriptFields = $transcripts[0]['fields'];
             // Create transcript and add to the database
             $transcript = new Transcript();
             $transcript->setText($transcriptText);
             $transcript->setFields($transcriptFields);
             $transcript->save(array('item' => $nextItem, 'status' => 'draft', 'type' => 'review'));
         }
         // Reload the user's queue, this time ignoring items they've already done
         // Add it to the user's queue
         $userQueue = new Queue("user.{$type}:{$username}", false);
         $userQueue->add($nextItem);
         $userQueue->save();
         // Remove it from the project queue
         $queue->remove($nextItem);
         $queue->save();
         $success = true;
         $code = $nextItem->item_id;
     } else {
         $code = "no-item-available";
     }
     return array('status' => $success, 'code' => $code);
 }