/** * Verifies 'enforce private' setting when creating pastes */ public function testPostCreatePrivateSite() { $this->initTestStep(); Site::config('general', array('paste_visibility' => 'private')); $key = 'UnitTest::Protected' . str_random(64); $response = $this->call('POST', 'create', array('title' => 'UnitTest::Title', 'data' => $key, 'language' => 'text')); Site::config('general', array('paste_visibility' => 'default')); $this->assertRedirectedTo($response->getTargetUrl()); $this->assertEquals(Paste::where('data', $key)->first()->private, 1); }
/** * Tests the getPaste's 'delete-paste' action */ public function testGetPasteDeletePaste() { $this->initTestStep(); $paste = Paste::createNew('web', array('title' => 'UnitTest::Title', 'data' => 'UnitTest::Data', 'language' => 'text', 'attachment' => array(true))); File::put(storage_path() . "/uploads/{$paste->urlkey}", 'attachment'); $this->call('GET', "{$paste->urlkey}/{$paste->hash}/delete"); $this->assertSessionHas('messages.success'); $this->assertRedirectedTo('/'); $this->assertEquals(Paste::where('id', $paste->id)->count(), 0); $this->assertFalse(File::exists(storage_path() . "/uploads/{$paste->urlkey}")); }
/** * Generates a short URL for a paste * * @param string $urlkey * @param string $hash * @return \Illuminate\Support\Facades\View|string */ public function getShorten($urlkey, $hash = '') { // We need to validate the paste first $paste = Paste::where('urlkey', $urlkey)->first(); // Paste was not found if (is_null($paste)) { return Lang::get('ajax.error'); } // If it is a private paste, we need the hash if ($paste->private and $paste->hash != $hash) { return Lang::get('ajax.error'); } // Shorten and return the paste URL $longUrl = url("{$urlkey}/{$hash}"); return Service::urlShortener($longUrl); }
/** * Gets the news feed for the site * * @param string $type * @return void */ public function getFeed($type = 'rss') { // Create feeder instance $feed = Feed::make($type); // Only the public pastes are accessible in the feed $query = Paste::where('private', '<>', 1); // We fetch 100 pastes only $pastes = $query->take(100)->orderBy('id', 'desc')->get(); // We populate the data manually here as there is some // per item processing to be done $list = array(); // Get the key for each paste item foreach ($pastes as $paste) { $list[] = $paste->toArray(); } // Serve the feed output return $feed->out(array('pastes' => $list)); }
// Prepend 'p' to non-empty URL keys DB::update("UPDATE {$dbPrefix}main SET urlkey = CONCAT('p', urlkey) WHERE urlkey <> ''"); // Setup admin = true for all users because // for 0.4, only admins could log in DB::update("UPDATE {$dbPrefix}users SET admin = 1"); // Set user type = ldap for users without passwords DB::update("UPDATE {$dbPrefix}users SET type = 'ldap' WHERE password = ''"); // Drop the session table, we no longer need it DB::update("DROP TABLE {$dbPrefix}session"); // Drop the cron table, we use cache to handle that now DB::update("DROP TABLE {$dbPrefix}cron"); // Generate URL keys for pastes that do not have a key. // We process the pastes in batches of 1000 to avoid running // out of memory. while (TRUE) { $pastes = Paste::where('urlkey', '')->take(1000)->get(array('id', 'urlkey')); if ($pastes->count() > 0) { foreach ($pastes as $paste) { $paste->urlkey = Paste::makeUrlKey(); $paste->save(); } } else { break; } } // Get the FQDN for the server $fqdn = getenv('SERVER_NAME'); // Insert fqdn, app version and migration ID to site config // The migration ID is nothing but the max paste ID while updating // This will be used to allow/deny access to old pastes by their IDs Site::config('general', array('fqdn' => $fqdn, 'preMigrate' => Paste::max('id')));
/** * Tests the getPaste method's 'delete' action */ public function testGetPasteDelete() { $this->initTestStep(); $paste = Paste::createNew('web', array('title' => 'UnitTest::Title', 'data' => 'UnitTest::Data', 'language' => 'text')); $this->call('GET', "admin/paste/{$paste->urlkey}/delete"); $this->assertRedirectedTo('admin/paste'); $this->assertEquals(Paste::where($paste->id)->count(), 0); }
/** * Triggers download action for a paste's attachment * * @param string $urlkey * @param string $hash * @return \Illuminate\Support\Facades\View */ public function getAttachment($urlkey, $hash = '') { $paste = Paste::where('urlkey', $urlkey)->first(); // Paste and/or attachment was not found if (is_null($paste)) { App::abort(404); // Not found } // Check if the logged in user is the owner of the paste $owner = Auth::access($paste->author_id); // We do not make password prompt mandatory for owners if (!$owner) { // Require hash to be passed for private pastes if ($paste->private and $paste->hash != $hash) { App::abort(401); // Unauthorized } // Check if paste is password protected and user hasn't entered // the password yet if ($paste->password and !Session::has('paste.password' . $paste->id)) { return View::make('site/password', array()); } } // Find the attachment, and process the download if ($paste->attachment) { $pathToFile = storage_path() . "/uploads/{$paste->urlkey}"; if (File::exists($pathToFile)) { return Response::download($pathToFile); } } // If we are here, the attachment wasn't found App::abort(404); }
/** * Editor window for creating a revision * * @param string $urlkey * @return \Illuminate\Support\Facades\View|\Illuminate\Support\Facades\Redirect */ public function getRevision($urlkey) { $paste = Paste::where('urlkey', $urlkey)->first(); // Paste was not found if (is_null($paste)) { App::abort(404); // Not found } else { // We only allow the user to revise public pastes // Private pastes need to be toggled before being revised if ($paste->private or $paste->password) { Session::flash('messages.error', Lang::get('create.revise_private')); return Redirect::to(URL::previous())->withInput(); } // Now that we are good, we save the paste ID in session so that // when the edited paste is POSTed, we can validate against this Session::put('paste.revision', $paste->id); } // Output the view $data = array('languages' => Highlighter::make()->languages(), 'language' => 'text', 'paste' => $paste, 'action' => 'CreateController@postRevision', 'disabled' => 'disabled', 'attach' => FALSE); return View::make('site/create', $data); }
/** * Tests the postCreate method of the controller without * guest posts enabled */ public function testPostCreateNoGuest() { $this->initTestStep(FALSE); Site::config('general', array('guest_posts' => '0')); $key = 'UnitTest::Protected' . str_random(64); $response = $this->call('POST', 'create', array('title' => 'UnitTest::Title', 'data' => $key, 'language' => 'text')); $this->assertSessionHas('messages.error'); $this->assertEquals(Paste::where('data', $key)->count(), 0); }
/** * Gets a paste list in the specified mode * * @param string $mode * @param int $page * @return \Illuminate\Support\Facades\View */ public function getList($mode, $page = 1) { $api = API::make($mode); $perPage = Site::config('general')->perPage; // As laravel reads the page GET parameter, we need to // manually set it to use this page. DB::getPaginator()->setCurrentPage($page); // Only the public pastes are accessible via the API $query = Paste::where('private', '<>', 1); $pastes = $query->orderBy('id', 'desc')->paginate($perPage); // Check if no pastes were found if ($pastes->count() === 0) { return $api->error('no_pastes', 418); } // We populate the data manually here as there is some // per item processing to be done $list = array(); // Get the key for each paste item foreach ($pastes as $paste) { $list[] = $paste->toArray(); } // Build the API data and make the output $data = array('pastes' => $list, 'count' => $pastes->count(), 'pages' => $pastes->getLastPage()); return $api->out('list', $data); }
/** * Displays a list of flagged pastes * * @access public * @return \Illuminate\Support\Facades\View */ public function getFlagged() { $perPage = Site::config('general')->perPage; // Get all flagged pastes $query = Paste::where('flagged', 1); // Filter by project if (!empty($this->project)) { $query = $query->where('project', $this->project); } $pastes = $query->orderBy('id', 'desc')->paginate($perPage); return $this->getList($pastes, TRUE); }
/** * Tests the postCreate method of the controller * for the XML API */ public function testPostCreateXml() { $this->initTestStep(); $key = 'UnitTest::XML' . time(); $response = $this->call('POST', 'api/xml/create', array('data' => $key, 'language' => 'text')); $this->assertResponseOk(); $this->assertTrue(str_contains($response->headers->get('Content-Type'), 'text/xml')); $this->assertEquals(Paste::where('data', $key)->count(), 1); }
/** * Handles POST actions for the user module * * @return \Illuminate\Support\Facades\Redirect */ public function postUser() { if (Input::has('_save')) { $id = Input::get('id'); // Define validation rules $validator = Validator::make(Input::all(), array('username' => 'required|max:50|alpha_dash|unique:users,username,' . $id . ',id,type,db', 'email' => 'required|max:100|email|unique:users,email,' . $id . ',id,type,db', 'dispname' => 'max:100', 'password' => empty($id) ? 'required|min:5' : 'min:5')); // Run the validator if ($validator->passes()) { // If ID is there, it is an update operation if (!empty($id)) { $user = User::findOrFail($id); $origUsername = $user->username; } else { $user = new User(); $origUsername = NULL; } $user->username = Input::get('username'); $user->email = Input::get('email'); $user->dispname = Input::get('dispname'); $user->salt = $user->salt ?: str_random(5); // The first user is always immutable $isFounder = $user->id == User::min('id'); $user->admin = $isFounder ?: Input::has('admin'); $user->active = $isFounder ?: Input::has('active'); if (Input::has('password')) { $user->password = PHPass::make()->create(Input::get('password'), $user->salt); } $user->save(); // Username is cached in the main, comment and revision tables, update them too if (!empty($id)) { Paste::where('author_id', $id)->update(array('author' => $user->username)); Revision::where('author', $origUsername)->update(array('author' => $user->username)); Comment::where('author', $origUsername)->update(array('author' => $user->username)); } Cache::flush(); Session::flash('messages.success', Lang::get('admin.user_saved')); return Redirect::to('admin/user'); } else { Session::flash('messages.error', $validator->messages()->all('<p>:message</p>')); return Redirect::to(URL::previous())->withInput(); } } else { if (Input::has('search')) { $username = Input::get('search'); return Redirect::to('admin/user/edit/' . urlencode($username)); } else { return Redirect::to('admin/user'); } } }
/** * Handles POST requests on the user profile * * @access public * @return \Illuminate\Support\Facades\Redirect */ public function postProfile() { $user = Auth::user(); // Define validation rules $rules = array('username' => 'max:50|alpha_dash|unique:users,username,' . $user->id . ',id,type,db', 'email' => 'required|max:100|email|unique:users,email,' . $user->id . ',id,type,db', 'dispname' => 'max:100', 'password' => 'min:5'); $validator = Validator::make(Input::all(), $rules); // Run the validator if ($validator->passes()) { $origUsername = $user->username; $user->username = $user->admin ? Input::get('username') : $user->username; $user->email = Input::get('email'); $user->dispname = Input::get('dispname'); if (Input::has('password')) { $user->password = PHPass::make()->create(Input::get('password'), $user->salt); } $user->save(); // Update cached username in the main table Paste::where('author_id', $user->id)->update(array('author' => $user->username)); // Update cached username in the revisions table Revision::where('author', $origUsername)->update(array('author' => $user->username)); // Update cached username in the comments table Comment::where('author', $origUsername)->update(array('author' => $user->username)); Session::flash('messages.success', Lang::get('user.profile_saved')); return Redirect::to('user/profile'); } else { Session::flash('messages.error', $validator->messages()->all('<p>:message</p>')); return Redirect::to('user/profile')->withInput(); } }