/** * {@inheritdoc} */ public function connect(Application $app) { $controllers = $app['controllers_factory']; $controllers->get('/login', function (Application $app, Request $request) { $username = $request->get('username'); $password = $request->get('password'); if (!strlen(trim($username)) || !strlen(trim($password))) { return H::apiError('Username and password are two required fields.'); } @(list($auth, $apisecret) = $app['lamest']->verifyUserCredentials($username, $password)); if (!isset($auth)) { return H::apiError('No match for the specified username / password pair.'); } return H::apiOK(array('auth' => $auth, 'apisecret' => $apisecret)); }); $controllers->post('/logout', function (Application $app, Request $request) { if (!H::isRequestValid($app['user'], $request->get('apisecret'), $error)) { return $error; } $app['lamest']->updateAuthToken($app['user']['id']); return H::apiOK(); }); $controllers->post('/create_account', function (Application $app, Request $request) { $engine = $app['lamest']; $username = $request->get('username'); $password = $request->get('password'); if (!strlen(trim($username)) || !strlen(trim($password))) { return H::apiError('Username and password are two required fields.'); } if ($engine->rateLimited(3600 * 15, array('create_user', $request->getClientIp()))) { return H::apiError('Please wait some time before creating a new user.'); } if (strlen($password) < ($minPwdLen = $engine->getOption('password_min_length'))) { return H::apiError("Password is too short. Min length: {$minPwdLen}"); } $authToken = $engine->createUser($username, $password); if (!$authToken) { return H::apiError('Username is busy. Please select a different one.'); } return H::apiOK(array('auth' => $authToken)); }); $controllers->post('/submit', function (Application $app, Request $request) { if (!H::isRequestValid($app['user'], $request->get('apisecret'), $error)) { return $error; } $engine = $app['lamest']; $newsID = $request->get('news_id'); $title = $request->get('title'); $url = $request->get('url'); $text = $request->get('text'); // We can have an empty url or an empty first comment, but not both. if (empty($newsID) || empty($title) || !strlen(trim($url)) && !strlen(trim($text))) { return H::apiError('Please specify a news title and address or text.'); } // Make sure the news has an accepted URI scheme (only http or https for now). if (!empty($url)) { $scheme = parse_url($url, PHP_URL_SCHEME); if ($scheme !== 'http' && $scheme !== 'https') { return H::apiError('We only accept http:// and https:// news.'); } } if ($newsID == -1) { if (($eta = $engine->getNewPostEta($app['user'])) > 0) { return H::apiError("You have submitted a story too recently, please wait {$eta} seconds."); } $newsID = $engine->insertNews($title, $url, $text, $app['user']['id']); } else { $newsID = $engine->editNews($app['user'], $newsID, $title, $url, $text); if (!$newsID) { return H::apiError('Invalid parameters, news too old to be modified or URL recently posted.'); } } return H::apiOK(array('news_id' => $newsID)); }); $controllers->post('/delnews', function (Application $app, Request $request) { if (!H::isRequestValid($app['user'], $request->get('apisecret'), $error)) { return $error; } $newsID = $request->get('news_id'); if (empty($newsID)) { return H::apiError('Please specify a news title.'); } if (!$app['lamest']->deleteNews($app['user'], $newsID)) { return H::apiError('News too old or wrong ID/owner.'); } return H::apiOK(array('news_id' => -1)); }); $controllers->post('/votenews', function (Application $app, Request $request) { if (!H::isRequestValid($app['user'], $request->get('apisecret'), $error)) { return $error; } $newsID = $request->get('news_id'); $voteType = $request->get('vote_type'); if (empty($newsID) || $voteType !== 'up' && $voteType !== 'down') { return H::apiError('Missing news ID or invalid vote type.'); } if ($app['lamest']->voteNews($newsID, $app['user'], $voteType, $error) === false) { return H::apiError($error); } return H::apiOK(); }); $controllers->post('/postcomment', function (Application $app, Request $request) { if (!H::isRequestValid($app['user'], $request->get('apisecret'), $error)) { return $error; } $newsID = $request->get('news_id'); $commentID = $request->get('comment_id'); $parentID = $request->get('parent_id'); $comment = $request->get('comment'); if (empty($newsID) || empty($commentID) || empty($parentID) || !isset($comment)) { return H::apiError('Missing news_id, comment_id, parent_id, or comment parameter.'); } $info = $app['lamest']->handleComment($app['user'], $newsID, $commentID, $parentID, $comment); if (!$info) { return H::apiError('Invalid news, comment, or edit time expired.'); } return H::apiOK(array('op' => $info['op'], 'comment_id' => $info['comment_id'], 'parent_id' => $parentID, 'news_id' => $newsID)); }); $controllers->post('/votecomment', function (Application $app, Request $request) { if (!H::isRequestValid($app['user'], $request->get('apisecret'), $error)) { return $error; } $compositeID = $request->get('comment_id'); $voteType = $request->get('vote_type'); if (!preg_match('/^\\d+-\\d+$/', $compositeID) || $voteType !== 'up' && $voteType !== 'down') { return H::apiError('Missing or invalid comment ID or invalid vote type.'); } list($newsID, $commentID) = explode('-', $compositeID); if (!$app['lamest']->voteComment($app['user'], $newsID, $commentID, $voteType)) { return H::apiError('Invalid parameters or duplicated vote.'); } return H::apiOK(array('comment_id' => $compositeID)); }); $controllers->post('/updateprofile', function (Application $app, Request $request) { if (!H::isRequestValid($app['user'], $request->get('apisecret'), $error)) { return $error; } $about = $request->get('about'); $email = $request->get('email'); $password = $request->get('password'); $attributes = array('about' => $about, 'email' => $email); if (($pwdLen = strlen($password)) > 0) { if ($pwdLen < ($minPwdLen = $app['lamest']->getOption('password_min_length'))) { return H::apiError("Password is too short. Min length: {$minPwdLen}"); } $attributes['password'] = H::pbkdf2($password, $app['user']['salt']); } $app['lamest']->updateUserProfile($app['user'], $attributes); return H::apiOK(); }); $controllers->get('/getnews/{sort}/{start}/{count}', function (Application $app, $sort, $start, $count) { $engine = $app['lamest']; if ($sort !== 'latest' && $sort !== 'top') { return H::apiError('Invalid sort parameter'); } if ($count > $engine->getOption('api_max_news_count')) { return H::apiError('Count is too big'); } if ($start < 0) { $start = 0; } $newslist = $engine->{"get{$sort}News"}($app['user'], $start, $count); foreach ($newslist['news'] as &$news) { unset($news['rank'], $news['score'], $news['user_id']); } return H::apiOK(array('news' => $newslist['news'], 'count' => $newslist['count'])); }); $controllers->get('/getcomments/{newsID}', function (Application $app, $newsID) { $engine = $app['lamest']; $user = $app['user']; @(list($news) = $engine->getNewsByID($user, $newsID)); if (!$news) { return H::apiError('Wrong news ID.'); } $topcomments = array(); $thread = $engine->getNewsComments($user, $news); foreach ($thread as $parentID => &$replies) { if ($parentID == -1) { $topcomments =& $replies; } foreach ($replies as &$reply) { $poster = $engine->getUserByID($reply['user_id']) ?: H::getDeletedUser(); $reply['username'] = $poster['username']; if (isset($thread[$reply['id']])) { $reply['replies'] =& $thread[$reply['id']]; } else { $reply['replies'] = array(); } if (!H::commentVoted($user, $reply)) { unset($reply['voted']); } if (isset($reply['up'])) { $reply['up'] = count($reply['up']); } if (isset($reply['down'])) { $reply['down'] = count($reply['down']); } unset($reply['user'], $reply['id'], $reply['thread_id'], $reply['score'], $reply['parent_id'], $reply['user_id']); } } return H::apiOK(array('comments' => $topcomments)); }); return $controllers; }
/** * {@inheritdoc} */ public function connect(Application $app) { $controllers = $app['controllers_factory']; $controllers->get('/', function (Application $app) { $newslist = $app['lamest']->getTopNews($app['user']); return $app['twig']->render('newslist.html.twig', array('title' => 'Top news', 'head_title' => 'Top news', 'newslist' => $newslist['news'])); }); $controllers->get('/rss', function (Application $app, Request $request) { $newslist = $app['lamest']->getLatestNews($app['user']); $rss = $app['twig']->render('newslist.rss.twig', array('site_name' => 'Lamer News', 'description' => 'Latest news', 'newslist' => $newslist['news'])); return new Response($rss, 200, array('Content-Type' => 'text/xml')); }); $controllers->get('/latest/{start}', function (Application $app, $start) { $engine = $app['lamest']; $perpage = $engine->getOption('latest_news_per_page'); $newslist = $engine->getLatestNews($app['user'], $start, $perpage); return $app['twig']->render('newslist.html.twig', array('title' => 'Latest news', 'newslist' => $newslist['news'], 'pagination' => array('start' => $start, 'count' => $newslist['count'], 'perpage' => $perpage, 'linkbase' => 'latest'))); })->value('start', 0); $controllers->get('/saved/{start}', function (Application $app, $start) { if (!$app['user']) { return $app->redirect('/login'); } $engine = $app['lamest']; $perpage = $engine->getOption('latest_news_per_page'); $newslist = $engine->getSavedNews($app['user'], $start); return $app['twig']->render('newslist.html.twig', array('title' => 'Saved news', 'head_title' => 'Your saved news', 'newslist' => $newslist['news'], 'pagination' => array('start' => $start, 'count' => $newslist['count'], 'perpage' => $perpage, 'linkbase' => 'saved'))); })->value('start', 0); $controllers->get('/usercomments/{username}/{start}', function (Application $app, $username, $start) { $user = $app['lamest']->getUserByUsername($username); if (!$user) { return $app->abort(404, 'Non existing user'); } $perpage = $app['lamest']->getOption('user_comments_per_page'); $comments = $app['lamest']->getUserComments($user, $start ?: 0, $perpage); return $app['twig']->render('user_comments.html.twig', array('title' => "{$username} comments", 'comments' => $comments['list'], 'username' => $username, 'pagination' => array('start' => $start, 'count' => $comments['total'], 'perpage' => $perpage))); })->value('start', 0); $controllers->get('/login', function (Application $app) { return $app['twig']->render('login.html.twig', array('title' => 'Login')); }); $controllers->get('/logout', function (Application $app, Request $request) { $apisecret = $request->get('apisecret'); if (isset($app['user']) && H::verifyApiSecret($app['user'], $apisecret)) { $app['lamest']->updateAuthToken($app['user']['id']); } return $app->redirect('/'); }); $controllers->get('/submit', function (Application $app, Request $request) { if (!$app['user']) { return $app->redirect('/login'); } return $app['twig']->render('submit_news.html.twig', array('title' => 'Submit a new story', 'bm_url' => $request->get('u'), 'bm_title' => $request->get('t'))); }); $controllers->get('/news/{newsID}', function (Application $app, $newsID) { $engine = $app['lamest']; @(list($news) = $engine->getNewsByID($app['user'], $newsID)); if (!$news) { return $app->abort(404, 'This news does not exist.'); } return $app['twig']->render('news.html.twig', array('title' => $news['title'], 'news' => $news, 'user' => $engine->getUserByID($news['user_id']), 'comments' => $engine->getNewsComments($app['user'], $news))); }); $controllers->get('/comment/{newsID}/{commentID}', function (Application $app, $newsID, $commentID) { $engine = $app['lamest']; if (!($news = $engine->getNewsByID($app['user'], $newsID))) { return $app->abort(404, 'This news does not exist.'); } if (!($comment = $engine->getComment($newsID, $commentID))) { return $app->abort(404, 'This comment does not exist.'); } if (!($user = $engine->getUserByID($comment['user_id']))) { $user = H::getDeletedUser(); } list($news) = $news; return $app['twig']->render('permalink_to_comment.html.twig', array('title' => $news['title'], 'news' => $news, 'comment' => array_merge($comment, array('id' => $commentID, 'user' => $user, 'voted' => H::commentVoted($app['user'], $comment))), 'comments' => $engine->getNewsComments($app['user'], $news))); }); $controllers->get('/reply/{newsID}/{commentID}', function (Application $app, $newsID, $commentID) { $engine = $app['lamest']; if (!$app['user']) { return $app->redirect('/login'); } if (!($news = $engine->getNewsByID($app['user'], $newsID))) { return $app->abort(404, 'This news does not exist.'); } if (!($comment = $engine->getComment($newsID, $commentID))) { return $app->abort(404, 'This comment does not exist.'); } if (!($user = $engine->getUserByID($comment['user_id']))) { $user = H::getDeletedUser(); } list($news) = $news; return $app['twig']->render('reply_to_comment.html.twig', array('title' => 'Reply to comment', 'news' => $news, 'comment' => array_merge($comment, array('id' => $commentID, 'user' => $user, 'voted' => H::commentVoted($app['user'], $comment))))); }); $controllers->get('/replies', function (Application $app) { $engine = $app['lamest']; if (!$app['user']) { return $app->redirect('/login'); } $perpage = $engine->getOption('subthreads_in_replies_page') - 1; $comments = $engine->getReplies($app['user'], $perpage, true); return $app['twig']->render('user_replies.html.twig', array('title' => 'Your threads', 'comments' => $comments)); }); $controllers->get('/editcomment/{newsID}/{commentID}', function (Application $app, $newsID, $commentID) { $engine = $app['lamest']; if (!$app['user']) { return $app->redirect('/login'); } if (!($news = $engine->getNewsByID($app['user'], $newsID))) { return $app->abort(404, 'This news does not exist.'); } if (!($comment = $engine->getComment($newsID, $commentID))) { return $app->abort(404, 'This comment does not exist.'); } $user = $engine->getUserByID($comment['user_id']); if (!$user || $app['user']['id'] != $user['id']) { return $app->abort(500, 'Permission denied.'); } list($news) = $news; return $app['twig']->render('edit_comment.html.twig', array('title' => 'Edit comment', 'news' => $news, 'comment' => array_merge($comment, array('id' => $commentID, 'user' => $user, 'voted' => H::commentVoted($app['user'], $comment))))); }); $controllers->get('/editnews/{newsID}', function (Application $app, $newsID) { $engine = $app['lamest']; if (!$app['user']) { return $app->redirect('/login'); } if (!($news = $engine->getNewsByID($app['user'], $newsID))) { return $app->abort(404, 'This news does not exist.'); } list($news) = $news; $user = $engine->getUserByID($news['user_id']); if (!$user || $app['user']['id'] != $user['id']) { return $app->abort(500, 'Permission denied.'); } $text = ''; if (!H::getNewsDomain($news)) { $text = H::getNewsText($news); $news['url'] = ''; } return $app['twig']->render('edit_news.html.twig', array('title' => 'Edit news', 'news' => $news, 'text' => $text)); }); $controllers->get('/user/{username}', function (Application $app, $username) { $engine = $app['lamest']; $user = $engine->getUserByUsername($username); if (!$user) { return $app->abort(404, 'Non existing user'); } return $app['twig']->render('userprofile.html.twig', array('title' => $username, 'user' => $user, 'user_counters' => $engine->getUserCounters($user))); }); return $controllers; }
/** * {@inheritdoc} */ public function voteComment(array $user, $newsID, $commentID, $type) { if ($type !== 'up' && $type !== 'down') { return false; } $comment = $this->getComment($newsID, $commentID); if (!$comment) { return false; } if (H::commentVoted($user, $comment)) { return false; } $votes[] = (int) $user['id']; return $this->editComment($newsID, $commentID, array($type => $votes)); }
/** * Verifies if the request for the user is valid. * * @param array $user User details. * @param string $apisecret API secret token. * @param string $response Error message on invalid requests. * @return boolean */ public static function isRequestValid(array $user, $apisecret, &$response) { if (!$user) { $response = Helpers::apiError('Not authenticated.'); return false; } if (!Helpers::verifyApiSecret($user, $apisecret)) { $response = Helpers::apiError('Wrong form secret.'); return false; } return true; }