CMS for the late garbage.fm
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add file caching, mp3 file uploading

+147 -62
+33 -12
controllers/admin_controller.php
··· 17 17 18 18 static $filter_parameter_logging = array("password"); 19 19 20 - public function index() { 21 - $this->episodes = Episode::find("all"); 22 - } 23 - 24 - public function login() { 25 - $this->page_title = "Login"; 26 - } 27 - 28 20 public function auth() { 29 21 if ($user = User::find_by_username($this->params["username"])) { 30 22 if ($user->password_matches($this->params["password"])) { ··· 40 32 return $this->render(array("action" => "login")); 41 33 } 42 34 35 + public function flushcache() { 36 + if (\HalfMoon\Utils::is_blank(\HalfMoon\Config::instance()->cache_store_path)) 37 + return redirect_to(ADMIN_ROOT); 38 + 39 + $deleted = 0; 40 + 41 + $fs = new RecursiveIteratorIterator( 42 + new RecursiveDirectoryIterator(\HalfMoon\Config::instance()->cache_store_path), 43 + RecursiveIteratorIterator::SELF_FIRST); 44 + foreach($fs as $name => $object) { 45 + if (is_file($name)) { 46 + unlink($name); 47 + $deleted++; 48 + } 49 + } 50 + 51 + $this->add_flash_success("Deleted " . $deleted . " cached file" 52 + . ($deleted == 1 ? "" : "s")); 53 + 54 + return $this->redirect_to(ADMIN_ROOT); 55 + } 56 + 57 + public function index() { 58 + $this->episodes = Episode::find("all"); 59 + } 60 + 61 + public function login() { 62 + $this->page_title = "Login"; 63 + } 64 + 43 65 public function logout() { 44 66 if ($this->user) 45 67 session_destroy(); ··· 49 71 return $this->redirect_to("/"); 50 72 } 51 73 74 + public function show_settings() { 75 + } 76 + 52 77 public function update_notes() { 53 78 $this->user->upcoming_notes = $this->params["upcoming_notes"]; 54 79 $this->user->save(); 55 80 56 81 $this->add_flash_success("Your upcoming show notes have been saved."); 57 82 return $this->redirect_to(ADMIN_ROOT); 58 - } 59 - 60 - public function show_settings() { 61 - $this->settings = $this->settings(); 62 83 } 63 84 64 85 public function update_show_settings() {
+26 -1
controllers/admin_episodes_controller.php
··· 8 8 ); 9 9 static $layout = "admin"; 10 10 11 + static $verify = array( 12 + array("method" => "post", 13 + "only" => array("create", "update", "destroy"), 14 + "redirect_to" => ADMIN_ROOT, 15 + ), 16 + ); 17 + 11 18 static $filter_parameter_logging = array("preview_text"); 12 19 20 + public function destroy() { 21 + $this->episode = Episode::find_by_episode($this->params["id"]); 22 + $this->episode->delete(); 23 + 24 + $this->add_flash_success("Successfully deleted episode " 25 + . h($this->episode->episode)); 26 + return $this->redirect_to(ADMIN_ROOT); 27 + } 28 + 13 29 public function index() { 14 30 $this->episodes = Episode::find("all", 15 31 array("order" => "episode DESC")); ··· 24 40 $this->episode->episode = $max + 1; 25 41 26 42 $this->episode->is_pending = true; 43 + $this->episode->air_date = new DateTime(date("Y-m-d 20:00:00")); 27 44 28 - $this->episode->air_date = new DateTime(date("Y-m-d 20:00:00")); 45 + $this->page_title = "Create New Episode"; 29 46 } 30 47 31 48 public function create() { 32 49 $this->episode = new Episode($this->params["episode"]); 50 + 51 + if ($_FILES["episode"]["name"]["new_mp3"]) 52 + $this->episode->take_new_mp3($_FILES["episode"]["tmp_name"]["new_mp3"]); 53 + 33 54 if ($this->episode->save()) { 34 55 $this->add_flash_success("Successfully created episode " . 35 56 $this->episode->episode); ··· 46 67 47 68 public function update() { 48 69 $this->episode = Episode::find_by_episode($this->params["id"]); 70 + 71 + if ($_FILES["episode"]["name"]["new_mp3"]) 72 + $this->episode->take_new_mp3($_FILES["episode"]["tmp_name"]["new_mp3"]); 73 + 49 74 if ($this->episode->update_attributes($this->params["episode"])) { 50 75 $this->add_flash_success("Successfully updated episode " . 51 76 h($this->episode->episode));
+3 -1
controllers/episodes_controller.php
··· 1 1 <?php 2 2 3 3 class EpisodesController extends ApplicationController { 4 + static $caches_page = array("index", "show", "rss"); 5 + 4 6 public function index() { 5 7 $this->episodes = Episode::find("all", 6 8 array("order" => "episode DESC")); 7 9 8 - $this->render(array("action" => "index")); 10 + $this->page_title = "Episodes"; 9 11 } 10 12 11 13 public function rss() {
+27 -7
models/Episode.php
··· 7 7 array("notes"), 8 8 array("duration_secs"), 9 9 array("air_date"), 10 + array("filesize"), 10 11 ); 11 12 static $validates_uniqueness_of = array( 12 13 array("episode"), ··· 14 15 15 16 static $attr_accessible = array( 16 17 "episode", "is_pending", "air_date", "title", "is_explicit", 17 - "duration_secs", "notes", "filesize", "summary", 18 + "duration_secs", "notes", "summary", 18 19 ); 19 20 20 - public function mp3_url() { 21 - return Settings::fetch()->url . "episodes/garbage" . $this->episode 22 - . ".mp3"; 21 + static $after_destroy = array("delete_mp3_file"); 22 + 23 + public function get_file_path() { 24 + return "episodes/garbage" . intval($this->episode) . ".mp3"; 25 + } 26 + 27 + public function get_mp3_url() { 28 + return Settings::fetch()->url . $this->file_path; 23 29 } 24 30 25 - public function absolute_url() { 31 + public function get_mp3_path() { 32 + return HALFMOON_ROOT . "/public/" . $this->file_path; 33 + } 34 + 35 + /* publicly viewable page, not mp3 */ 36 + public function get_absolute_url() { 26 37 return Settings::fetch()->url . "episodes/" . $this->episode; 27 38 } 28 39 29 - public function artwork_url() { 40 + public function get_artwork_url() { 30 41 return Settings::fetch()->logo_url; 31 42 } 32 43 33 - public function notes_html() { 44 + public function get_notes_html() { 34 45 $parsedown = new Parsedown(); 35 46 return $parsedown->text($this->notes); 47 + } 48 + 49 + public function take_new_mp3($file) { 50 + move_uploaded_file($file, $this->mp3_path); 51 + $this->filesize = filesize($this->mp3_path); 52 + } 53 + 54 + public function delete_mp3_file() { 55 + unlink($this->mp3_path); 36 56 } 37 57 } 38 58
-3
public/404.html
··· 6 6 </head> 7 7 <body> 8 8 <h1>File not found</h1> 9 - <p> 10 - Change this error message for pages not found in <tt>public/404.html</tt> 11 - </p> 12 9 </body> 13 10 </html>
+1 -1
public/500.html
··· 7 7 <body> 8 8 <h1>Application error</h1> 9 9 <p> 10 - Change this error message in <tt>public/500.html</tt> 10 + :( 11 11 </p> 12 12 </body> 13 13 </html>
+4 -2
public/stylesheets/application.css
··· 215 215 } 216 216 div#subheader a { 217 217 color: gray; 218 + font-weight: bold; 218 219 } 219 220 220 - div#header h1 { 221 + div#header h2 { 221 222 margin: 0px; 222 223 padding: 0px; 223 224 } 224 - div#header h1 a { 225 + div#header h2 a { 225 226 color: white; 226 227 text-decoration: none; 227 228 } ··· 247 248 margin-top: 2em; 248 249 padding-top: 1em; 249 250 padding-bottom: 2em; 251 + text-align: right; 250 252 } 251 253 div#footer a { 252 254 color: gray;
+14 -13
views/admin/index.phtml
··· 1 - <h3>Episodes (<a href="<?= ADMIN_ROOT ?>episodes/build">Create New</a>)</h3> 2 - 3 - <ul> 4 - <? foreach ($C->episodes as $episode) { ?> 5 - <li><a href="<?= ADMIN_ROOT ?>episodes/edit/<?= $episode->episode ?>"><?= 6 - $episode->episode ?>: <?= h($episode->title) ?></a> 7 - (<?= $episode->air_date->format("Y-m-d") ?>) 8 - <? if ($episode->is_pending) { ?> 9 - (<strong>PENDING</strong>) 10 - <? } ?> 11 - <? } ?> 12 - </ul> 13 - 14 1 <p> 15 2 <h3>Upcoming Show Notes/Scratch</h3> 16 3 </p> ··· 45 32 </div> 46 33 <? } ?> 47 34 </div> 35 + 36 + <h3>Past Episodes (<a href="<?= ADMIN_ROOT ?>episodes/build">Create New</a>)</h3> 37 + 38 + <ul> 39 + <? foreach ($C->episodes as $episode) { ?> 40 + <li><a href="<?= ADMIN_ROOT ?>episodes/edit/<?= $episode->episode ?>"><?= 41 + $episode->episode ?>: <?= h($episode->title) ?></a> 42 + (<?= $episode->air_date->format("Y-m-d") ?>) 43 + <? if ($episode->is_pending) { ?> 44 + (<strong>PENDING</strong>) 45 + <? } ?> 46 + <? } ?> 47 + </ul> 48 +
+1 -1
views/admin/show_settings.phtml
··· 5 5 <h3>Edit Show Settings</h3> 6 6 7 7 <div class="box wide"> 8 - <? $form->form_for($C->settings, ADMIN_ROOT . "update_show_settings", 8 + <? $form->form_for($C->settings(), ADMIN_ROOT . "update_show_settings", 9 9 array(), function($f) use ($C) { ?> 10 10 <div class="boxline"> 11 11 <?= $f->label("name", "Show Name:", array("class" => "required")); ?>
+13 -3
views/admin_episodes/_form.phtml
··· 35 35 <div class="boxline"> 36 36 <?= $f->label("duration_secs", "Duration:", array("class" => "required")); ?> 37 37 <?= $f->text_field("duration_secs", array("style" => "width: 5em;")) ?> 38 - (seconds) 38 + seconds 39 39 </div> 40 40 41 + <? if ($f->form_object->id) { ?> 42 + <div class="boxline"> 43 + <?= $f->label("filesize", "File size:", array("class" => "required")); ?> 44 + <span class="d"> 45 + <?= $helper->bytes_h($f->form_object->filesize) ?> bytes 46 + </span> 47 + </div> 48 + <? } ?> 49 + 41 50 <div class="boxline"> 42 - <?= $f->label("filesize", "File size:", array("class" => "required")); ?> 43 - <?= $f->text_field("filesize", array("style" => "width: 5em;")) ?> (bytes) 51 + <?= $f->label("new_mp3", ($f->form_object->id ? "Replace " : "") 52 + . "MP3 file:", array("class" => "required")); ?> 53 + <?= $f->file_field("new_mp3") ?> 44 54 </div> 45 55 46 56 <div class="boxline">
+2 -2
views/admin_episodes/build.phtml
··· 5 5 <h3>New Episode</h3> 6 6 7 7 <div class="box wide"> 8 - <? $form->form_for($C->episode, ADMIN_ROOT . "episodes/create", array(), 9 - function($f) use ($C) { ?> 8 + <? $form->form_for($C->episode, ADMIN_ROOT . "episodes/create", 9 + array("multipart" => true), function($f) use ($C) { ?> 10 10 <?= $C->render(array("partial" => "form"), array("f" => $f)); ?> 11 11 <p> 12 12 <?= $f->submit_tag("Create"); ?>
+8 -1
views/admin_episodes/edit.phtml
··· 1 1 <div style="float: right;"> 2 + <strong> 3 + <?= $html->link_to("Delete", 4 + ADMIN_ROOT . "episodes/destroy/" . $episode->episode, 5 + array("confirm" => "Are you sure you want to delete this episode?", 6 + "method" => "post")); ?> 7 + </strong> 8 + | 2 9 <strong><a href="<?= ADMIN_ROOT ?>">Cancel</a></strong> 3 10 </div> 4 11 ··· 6 13 7 14 <div class="box wide"> 8 15 <? $form->form_for($C->episode, ADMIN_ROOT . "episodes/update/" . 9 - $episode->episode, array(), function($f) use ($C) { ?> 16 + $episode->episode, array("multipart" => true), function($f) use ($C) { ?> 10 17 <?= $C->render(array("partial" => "form"), array("f" => $f)); ?> 11 18 <p> 12 19 <?= $f->submit_tag("Update"); ?>
+4 -4
views/episodes/_episode.phtml
··· 1 1 <div class="episode"> 2 2 <div class="title"> 3 - <a href="<?= h($episode->absolute_url()) ?>"> 3 + <a href="<?= h($episode->absolute_url) ?>"> 4 4 garbage[<?= h($episode->episode) ?>]: <?= h($episode->title) ?> 5 5 </a> 6 6 <div class="date"> ··· 9 9 </div> 10 10 11 11 <audio controls> 12 - <source src="<?= h($episode->mp3_url()) ?>" type="audio/mpeg"> 12 + <source src="<?= h($episode->mp3_url) ?>" type="audio/mpeg"> 13 13 Your browser does not support the audio element - 14 14 </audio> 15 15 <div class="download"> 16 - <a href="<?= h($episode->mp3_url()) ?>">Download 16 + <a href="<?= h($episode->mp3_url) ?>">Download 17 17 (<?= $helper->bytes_h($episode->filesize) ?>)</a> 18 18 </div> 19 19 20 20 <div class="notes"> 21 - <?= $episode->notes_html() ?> 21 + <?= $episode->notes_html ?> 22 22 </div> 23 23 </div>
+5 -5
views/episodes/rss.pxml
··· 28 28 <item> 29 29 <title>garbage[<?= h($episode->episode) ?>]: <?= h($episode->title) ?></title> 30 30 <pubDate><?= $episode->air_date->format("r") ?></pubDate> 31 - <link><?= h($episode->absolute_url()) ?></link> 32 - <guid isPermaLink="false"><?= h($episode->absolute_url()) ?></guid> 31 + <link><?= h($episode->absolute_url) ?></link> 32 + <guid isPermaLink="false"><?= h($episode->absolute_url) ?></guid> 33 33 <description><![CDATA[ 34 - <?= $episode->notes_html() ?> 34 + <?= $episode->notes_html ?> 35 35 <p> 36 36 We welcome your feedback at <a 37 37 href="https://twitter.com/garbagefm">@garbagefm</a> on Twitter ··· 43 43 <itunes:summary><?= h($episode->summary) ?></itunes:summary> 44 44 <itunes:explicit><?= $episode->is_explicit ? "yes" : "no" ?></itunes:explicit> 45 45 <itunes:duration><?= h($episode->duration_secs) ?></itunes:duration> 46 - <itunes:image href="<?= h($episode->artwork_url()) ?>"/> 47 - <enclosure url="<?= h($episode->mp3_url()) ?>" 46 + <itunes:image href="<?= h($episode->artwork_url) ?>"/> 47 + <enclosure url="<?= h($episode->mp3_url) ?>" 48 48 length="<?= h($episode->filesize) ?>" type="audio/mpeg"/> 49 49 </item> 50 50 <? } ?>
+6 -6
views/layouts/admin.phtml
··· 6 6 <meta http-equiv="content-type" content="text/html; charset=utf-8"> 7 7 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 8 8 <link rel="shortcut icon" href="/garbage.png" /> 9 - <?php echo $html->stylesheet_link_tag(array("application")); ?> 10 - <?php echo $html->javascript_include_tag(array("prototype")); ?> 9 + <?= $html->stylesheet_link_tag(array("application")); ?> 10 + <?= $html->javascript_include_tag(array("prototype")); ?> 11 11 </head> 12 12 <body> 13 13 <div id="wrapper"> 14 14 <div id="header"> 15 15 <div id="headerright"> 16 - <? if ($controller->user) { ?> 16 + <? if ($C->user) { ?> 17 17 Logged in as 18 - <?= h($controller->user->username); ?> 18 + <?= h($C->user->username); ?> 19 19 <br> 20 20 <?= $html->link_to("Logout", 21 21 array("controller" => "admin", "action" => "logout"), ··· 26 26 <? } ?> 27 27 </div> 28 28 29 - <h1><a href="<?= ADMIN_ROOT ?>"><?= h($C->settings()->name) ?> 30 - - Administration</a></h1> 29 + <h2><a href="<?= ADMIN_ROOT ?>"><?= h($C->settings()->name) ?> 30 + - Administration</a></h2> 31 31 32 32 <div class="clear"></div> 33 33 </div>