public
Description: The ultra-lightweight ultra-flexible blogging engine with a fetish for birds and misspellings.
Homepage: http://chyrp.net/
Clone URL: git://github.com/vito/chyrp.git
Click here to lend your support to: chyrp and make a donation at www.pledgie.com !
* Group-specific post statuses. [#156 state:resolved]
* More common.php cleanups.
* Tester improvements.
* SQL->escape can be set to not auto-wrap with quotes with the first (bool) 
argument.
vito (author)
Sat Sep 06 22:17:22 -0700 2008
commit  40723b52d084891ccc2a05f46b9a191a885668c8
tree    c50a3dddf0376f9434409956c388e195250c989f
parent  a3d1c5c28f03588ac451190abd4957e766f56a19
...
43
44
45
46
 
47
48
49
 
50
51
52
...
43
44
45
 
46
47
48
 
49
50
51
52
0
@@ -43,10 +43,10 @@
0
         </thead>
0
         <tbody>
0
         {% for post in posts.paginated %}
0
-          <tr id="post_$post.id" class="post $post.status{% if loop.last %} last{% endif %}">
0
+          <tr id="post_$post.id" class="post $post.status_class{% if loop.last %} last{% endif %}">
0
             <td class="main"><a href="$post.url">${ post.title | truncate }</a></td>
0
             <td>${ post.created_at | strftime }</td>
0
-            <td>${ post.status | replace("_", " ") | title | translate }</td>
0
+            <td>$post.status_name</td>
0
             <td>$post.user.login</td>
0
             ${ trigger.call("manage_posts_column", post) }
0
 {% if post.editable and post.deletable %}
...
52
53
54
55
 
56
57
58
59
 
 
 
 
 
 
 
 
60
61
62
...
52
53
54
 
55
56
 
 
 
57
58
59
60
61
62
63
64
65
66
67
0
@@ -52,11 +52,16 @@
0
               <label for="status">${ "Status" | translate }</label>
0
               <select name="status" id="status">
0
 {% if route.action == "edit_post" %}
0
-                <option value="draft"{% if post.status == "draft" %} selected="selected"{% endif %}>${ "Draft" | translate }</option>
0
+                <option value="draft"${ post.status | option_selected("draft") }>${ "Draft" | translate }</option>
0
 {% endif %}
0
-                <option value="public"{% if post.status == "public" %} selected="selected"{% endif %}>${ "Public" | translate }</option>
0
-                <option value="private"{% if post.status == "private" %} selected="selected"{% endif %}>${ "Private" | translate }</option>
0
-                <option value="registered_only"{% if post.status == "registered_only" %} selected="selected"{% endif %}>${ "Registered Only" | translate }</option>
0
+                <option value="public"${ post.status | option_selected("public") }>${ "Public" | translate }</option>
0
+                <option value="private"${ post.status | option_selected("private") }>${ "Private" | translate }</option>
0
+                <option value="registered_only"${ post.status | option_selected("registered_only") }>${ "Registered Only" | translate }</option>
0
+                <optgroup label="${ "Group" | translate }">
0
+                  {% for group in groups %}
0
+                  <option value="{$group.id}"${ post.status | option_selected("{"~ group.id ~"}") }>${ group.name | escape }</option>
0
+                  {% endfor %}
0
+                </optgroup>
0
               </select>
0
             </p>
0
             {% endif %}
...
989
990
991
 
 
 
992
...
989
990
991
992
993
994
995
0
@@ -989,4 +989,7 @@ img.smiley {
0
   font-weight: bold;
0
   color: #bbb;
0
 }
0
+.group_prefix {
0
+  color: #999;
0
+}
0
 /* @end */
...
203
204
205
206
 
 
 
 
207
208
209
...
220
221
222
223
 
224
225
226
227
 
 
 
 
228
229
230
...
259
260
261
262
 
263
264
265
266
 
 
 
267
268
269
...
203
204
205
 
206
207
208
209
210
211
212
...
223
224
225
 
226
227
228
229
 
230
231
232
233
234
235
236
...
265
266
267
 
268
269
270
271
272
273
274
275
276
277
278
0
@@ -203,7 +203,10 @@
0
       }
0
     }
0
 
0
-    public function check_viewing_page($i_have_the_power = false) {
0
+    public function check_viewing_page() {
0
+      if (!INDEX)
0
+        return;
0
+
0
       global $page;
0
 
0
       $config = Config::current();
0
@@ -220,11 +223,14 @@
0
         foreach ($valids as $page)
0
           if ($page->url == end($this->arg))
0
             return list($_GET['url'], $this->action) = array($page->url, "page");
0
-      } elseif ($i_have_the_power)
0
+      } elseif (!preg_match("/^\((clean|url)\)\/?$/", $config->post_url)) # This is the last route parse.
0
         return $this->action = fallback($this->arg[0], "index");
0
     }
0
 
0
-    public function check_viewing_post($i_have_the_power = false) {
0
+    public function check_viewing_post() {
0
+      if (!INDEX)
0
+        return;
0
+
0
       $config = Config::current();
0
 
0
       if (!empty($this->action))
0
@@ -259,11 +265,14 @@
0
           return $this->action = "view";
0
       }
0
 
0
-      if ($i_have_the_power)
0
+      if (preg_match("/^\((clean|url)\)\/?$/", $config->post_url)) # This is the last route parse.
0
         return $this->action = fallback($this->arg[0], "index");
0
     }
0
 
0
     public function check_custom_routes() {
0
+      if (!INDEX)
0
+        return;
0
+
0
       $config = Config::current();
0
 
0
       # Custom pages added by Modules, Feathers, Themes, etc.
...
1
 
 
 
 
 
 
 
 
 
 
2
3
4
...
298
299
300
301
 
302
303
304
 
305
306
307
 
308
309
310
 
311
312
313
314
315
316
 
 
 
317
318
319
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
308
309
310
 
311
312
313
 
314
315
316
 
317
318
319
 
320
321
322
323
324
325
326
327
328
329
330
331
332
0
@@ -1,4 +1,14 @@
0
 <?php
0
+  # File: Query
0
+  # See Also:
0
+  #     <Query>
0
+  require_once INCLUDES_DIR."/class/Query.php";
0
+
0
+  # File: QueryBuilder
0
+  # See Also:
0
+  #     <QueryBuilder>
0
+  require_once INCLUDES_DIR."/class/QueryBuilder.php";
0
+
0
   /**
0
    * Class: SQL
0
    * Contains the database settings and functions for interacting with the SQL database.
0
@@ -298,22 +308,25 @@
0
      * Escapes a string, escaping things like $1 and C:\foo\bar so that they don't get borked by the preg_replace.
0
      * This also handles calling the SQL connection method's "escape_string" functions.
0
      */
0
-    public function escape($string) {
0
+    public function escape($string, $quotes = true) {
0
       switch(SQL::current()->method()) {
0
         case "pdo":
0
-          $string = $this->db->quote($string);
0
+          $string = ltrim(rtrim($this->db->quote($string), "'"), "'");
0
           break;
0
         case "mysqli":
0
-          $string = "'".$this->db->escape_string($string)."'";
0
+          $string = $this->db->escape_string($string);
0
           break;
0
         case "mysql":
0
-          $string = "'".mysql_real_escape_string($string)."'";
0
+          $string = mysql_real_escape_string($string);
0
           break;
0
       }
0
 
0
       $string = str_replace('\\', '\\\\', $string);
0
       $string = str_replace('$', '\$', $string);
0
 
0
+      if ($quotes)
0
+        $string = "'".$string."'";
0
+
0
       return $string;
0
     }
0
 
...
23
24
25
26
 
27
28
29
...
87
88
89
90
91
 
 
 
92
93
 
 
 
94
95
96
97
98
99
 
 
 
 
100
101
102
...
287
288
289
 
290
291
292
...
304
305
306
307
308
 
309
310
311
312
313
314
315
316
317
 
 
 
 
 
 
 
 
318
319
320
 
321
322
323
...
329
330
331
332
 
 
333
334
335
...
23
24
25
 
26
27
28
29
...
87
88
89
 
 
90
91
92
93
94
95
96
97
98
 
99
 
 
 
100
101
102
103
104
105
106
...
291
292
293
294
295
296
297
...
309
310
311
 
 
312
313
 
 
 
 
 
 
 
 
314
315
316
317
318
319
320
321
322
 
 
323
324
325
326
...
332
333
334
 
335
336
337
338
339
0
@@ -23,7 +23,7 @@
0
 
0
   # Constant: DEBUG
0
   # Should Chyrp use debugging processes?
0
-  define('DEBUG', false);
0
+  define('DEBUG', true);
0
 
0
   # Fallback all these definitions.
0
   if (!defined('JAVASCRIPT')) define('JAVASCRIPT', false);
0
@@ -87,16 +87,20 @@
0
   if (!file_exists(INCLUDES_DIR."/config.yaml.php"))
0
     redirect("install.php");
0
 
0
-  require_once INCLUDES_DIR."/class/Query.php";
0
-  require_once INCLUDES_DIR."/class/QueryBuilder.php";
0
+  # Libraries
0
+  require_once INCLUDES_DIR."/lib/gettext/gettext.php";
0
+  require_once INCLUDES_DIR."/lib/gettext/streams.php";
0
   require_once INCLUDES_DIR."/lib/YAML.php";
0
 
0
+  # File: Config
0
+  # See Also:
0
+  #     <Config>
0
   require_once INCLUDES_DIR."/class/Config.php";
0
-  require_once INCLUDES_DIR."/class/SQL.php";
0
 
0
-  # Translation stuff
0
-  require_once INCLUDES_DIR."/lib/gettext/gettext.php";
0
-  require_once INCLUDES_DIR."/lib/gettext/streams.php";
0
+  # File: SQL
0
+  # See Also:
0
+  #     <SQL>
0
+  require_once INCLUDES_DIR."/class/SQL.php";
0
 
0
   set_timezone($config->timezone);
0
 
0
@@ -287,6 +291,7 @@
0
                            !empty($_GET['action']) and
0
                            $_GET['action'] == "theme_preview" and
0
                            !empty($_GET['theme'])));
0
+
0
   $theme = PREVIEWING ? $_GET['theme'] : $config->theme;
0
 
0
   # Constant: THEME_DIR
0
@@ -304,20 +309,18 @@
0
 
0
   header("Content-type: ".(INDEX ? fallback($theme->type, "text/html") : "text/html")."; charset=UTF-8");
0
 
0
-  if (INDEX) {
0
-    $route->check_custom_routes();
0
+  $route->check_custom_routes();
0
 
0
-    # If the post viewing URL is the same as the page viewing URL, check for viewing a page first.
0
-    if (preg_match("/^\((clean|url)\)\/?$/", $config->post_url)) {
0
-      $route->check_viewing_page();
0
-      $route->check_viewing_post(true);
0
-    } else {
0
-      $route->check_viewing_page(true);
0
-      $route->check_viewing_post();
0
-    }
0
+  # If the post viewing URL is the same as the page viewing URL, check for viewing a page first.
0
+  if (preg_match("/^\((clean|url)\)\/?$/", $config->post_url)) {
0
+    $route->check_viewing_page();
0
+    $route->check_viewing_post();
0
+  } else {
0
+    $route->check_viewing_post();
0
+    $route->check_viewing_page();
0
+  }
0
 
0
-    $trigger->call("runtime");
0
-  } elseif (ADMIN)
0
+  if (INDEX or ADMIN)
0
     $trigger->call("runtime");
0
 
0
   # Array: $statuses
0
@@ -329,7 +332,8 @@
0
   if ($visitor->group()->can("view_private"))
0
     $statuses[] = "private";
0
 
0
-  Post::$private = "status IN ('".implode("', '", $statuses)."')";
0
+  Post::$private = "(status IN ('".implode("', '", $statuses)."') OR".
0
+                   " status LIKE '%{".$visitor->group()->id."}%')";
0
   Post::$enabled_feathers = "feather IN ('".implode("', '", $config->enabled_feathers)."')";
0
 
0
   # Load the translation engine
...
34
35
36
 
37
38
39
...
88
89
90
 
 
 
91
92
93
...
194
195
196
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
198
199
...
34
35
36
37
38
39
40
...
89
90
91
92
93
94
95
96
97
...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
0
@@ -34,6 +34,7 @@
0
 
0
       $this->context["feathers"]       = $feathers;
0
       $this->context["feather"]        = $feathers[$_GET['feather']];
0
+      $this->context["groups"]         = Group::find(array("order" => "id ASC"));
0
     }
0
 
0
     /**
0
@@ -88,6 +89,9 @@
0
 
0
       $post = $feathers[$_POST['feather']]->submit();
0
 
0
+      if (!$post->redirect)
0
+        $post->redirect = "/admin/?action=write_post";
0
+
0
       if (!isset($_POST['bookmarklet']))
0
         Flash::notice(__("Post created!"), $post->redirect);
0
       else
0
@@ -194,6 +198,25 @@
0
                                                                "drafts" => true,
0
                                                                "where" => $where,
0
                                                                "params" => $params)), 25);
0
+
0
+      foreach ($this->context["posts"]->paginated as &$post) {
0
+        if (preg_match_all("/\{([0-9]+)\}/", $post->status, $matches)) {
0
+          $groups = array();
0
+          $groupClasses = array();
0
+
0
+          foreach ($matches[1] as $id) {
0
+            $group = new Group($id);
0
+            $groups[] = "<span class=\"group_prefix\">Group:</span> ".$group->name;
0
+            $groupClasses[] = "group-".$id;
0
+          }
0
+
0
+          $post->status_name = join(", ", $groups);
0
+          $post->status_class = join(" ", $groupClasses);
0
+        } else {
0
+          $post->status_name = camelize($post->status, true);
0
+          $post->status_class = $post->status;
0
+        }
0
+      }
0
     }
0
 
0
     /**
...
36
37
38
39
 
40
41
42
...
76
77
78
79
 
80
81
82
...
36
37
38
 
39
40
41
42
...
76
77
78
 
79
80
81
82
0
@@ -36,7 +36,7 @@
0
       if (!XML_RPC) {
0
         $visitor = Visitor::current();
0
         $private = (isset($options["drafts"]) and $options["drafts"] and $visitor->group()->can("view_draft")) ?
0
-                       str_replace("')", "', 'draft')", self::$private) :
0
+                       str_replace("') OR", "', 'draft') OR", self::$private) :
0
                        self::$private;
0
 
0
         $options["where"][] = self::$enabled_feathers;
0
@@ -76,7 +76,7 @@
0
       if (!XML_RPC) {
0
         $visitor = Visitor::current();
0
         $private = (isset($options["drafts"]) and $options["drafts"] and $visitor->group()->can("view_draft")) ?
0
-                       str_replace("')", "', 'draft')", self::$private) :
0
+                       str_replace("') OR", "', 'draft') OR", self::$private) :
0
                        self::$private ;
0
 
0
         $options["where"][] = self::$enabled_feathers;
...
3
4
5
 
 
 
6
7
8
...
17
18
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
21
22
 
 
23
24
 
25
26
 
 
 
 
 
 
 
 
27
28
29
30
 
 
31
32
 
33
34
35
 
 
 
 
 
 
36
37
 
 
38
39
40
41
42
 
43
44
45
...
58
59
60
61
 
 
 
 
62
63
64
...
125
126
127
 
128
129
130
...
174
175
176
177
 
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
 
194
195
196
197
198
199
200
201
202
203
 
 
204
205
206
...
3
4
5
6
7
8
9
10
11
...
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
45
46
47
 
48
49
 
50
51
52
53
54
55
56
57
58
59
60
 
61
62
63
 
64
65
 
 
66
67
68
69
70
71
72
 
73
74
75
76
77
78
79
80
81
82
83
...
96
97
98
 
99
100
101
102
103
104
105
...
166
167
168
169
170
171
172
...
216
217
218
 
219
220
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
223
224
225
226
 
 
 
 
 
 
227
228
229
230
231
0
@@ -3,6 +3,9 @@ require "net/http"
0
 require "rubygems"
0
 require "hpricot"
0
 
0
+`rm -Rfv uploads/*`
0
+`mysql -f --user=root -D chyrp -e 'TRUNCATE TABLE chyrp_posts; TRUNCATE TABLE chyrp_pages; TRUNCATE TABLE chyrp_comments; TRUNCATE TABLE chyrp_tags;' > /dev/null`
0
+
0
 FUZZER = {
0
   :textarea => "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam urna. Vivamus nisl. Mauris iaculis rutrum elit. Cras ornare congue mi. Nullam mi quam, luctus dapibus, euismod ut, dapibus sed, dui. Praesent est lectus, rutrum ac, blandit vitae, hendrerit at, massa. Morbi mauris purus, lobortis vel, commodo vitae, aliquet vehicula, ante. Nunc commodo. Pellentesque vel lacus. Quisque eros. Maecenas et quam. Curabitur eget justo a ante dignissim dapibus. Sed et lacus. Suspendisse potenti. Vivamus ipsum mi, blandit vitae, scelerisque a, pellentesque vitae, nisl. Donec vitae est et est egestas laoreet. Vestibulum commodo elit ut nisl. Nullam volutpat nisi non elit. Morbi sapien eros, ornare et, dapibus id, mattis id, nibh. Suspendisse ut nisl id est scelerisque faucibus.\n\nPraesent viverra felis nec justo. Duis gravida tempor massa. Aliquam lobortis tortor eu purus. Phasellus volutpat, justo eget molestie rhoncus, nibh tortor suscipit justo, non vehicula tortor tortor id sapien. Vivamus quis nisl et neque ullamcorper viverra. Vestibulum accumsan, elit luctus auctor fermentum, lorem tellus dignissim odio, a lobortis magna nulla eget arcu. Phasellus vel erat at dolor sagittis luctus. Nulla facilisi. In eros eros, molestie sit amet, ornare a, fermentum et, dui. Vivamus vel turpis quis diam iaculis dapibus. Nunc lacinia. Integer commodo, urna interdum imperdiet pretium, libero nulla pellentesque turpis, in ultrices neque tortor at arcu. Sed mollis odio eget mauris ultricies bibendum. Vivamus malesuada metus vel arcu. Nam sit amet metus. Pellentesque quis felis non nibh adipiscing adipiscing.",
0
   :text => "Test Input"
0
@@ -17,29 +20,64 @@ HEADERS = {
0
   "User-Agent" => "tester.rb"
0
 }
0
 
0
+POSTS = {
0
+  :text => {
0
+    "title" => "Test Text Post",
0
+    "body" => FUZZER[:textarea]
0
+  },
0
+  :quote => {
0
+    "quote" => FUZZER[:textarea].split(". ")[0] + ".",
0
+    "source" => "Chyrp Tester"
0
+  },
0
+  :chat => {
0
+    "title" => "Test Chat Post",
0
+    "dialogue" => "Person: Hi!\nMe (me): Hello!\nPerson: How are you?\nMe: Great, thanks! And you?\nPerson: FUCKING AWESOME."
0
+  },
0
+  :link => {
0
+    "name" => "Google Search",
0
+    "source" => "http://google.com/",
0
+    "description" => "I can't believe how long I've gone without finding this site."
0
+  }
0
+}
0
+
0
 class Chyrp < Test::Unit::TestCase
0
   def test_add_post
0
-    resp, write = get "/admin/?action=write_post"
0
+    POSTS.each do |feather, attrs|
0
+      resp, write = get "/admin/?action=write_post&feather="+ feather.to_s
0
 
0
-    page = Hpricot(write)
0
+      page = Hpricot(write)
0
 
0
-    post (page/"form").attr("action"), form_fuzz(page/"form")
0
+      form_fuzz(page/"form").each do |key, val|
0
+        attrs[key] = val unless attrs.has_key? key
0
+      end
0
+
0
+      attrs['feather'] = feather.to_s
0
+
0
+      post (page/"form").attr("action"), attrs
0
+    end
0
   end
0
 
0
   def test_add_draft
0
-    resp, write = get "/admin/?action=write_post"
0
+    POSTS.each do |feather, attrs|
0
+      resp, write = get "/admin/?action=write_post&feather="+ feather.to_s
0
 
0
-    page = Hpricot(write)
0
+      page = Hpricot(write)
0
 
0
-    data = form_fuzz(page/"form")
0
-    data['draft'] = "true"
0
+      form_fuzz(page/"form").each do |key, val|
0
+        attrs[key] = val unless attrs.has_key? key
0
+      end
0
+
0
+      attrs['feather'] = feather.to_s
0
+      attrs['draft'] = "true"
0
 
0
-    post (page/"form").attr("action"), data
0
+      post (page/"form").attr("action"), attrs
0
+    end
0
   end
0
 
0
   def test_view_post
0
     resp, page = test_index
0
     page = Hpricot(page)
0
+    return unless page =~ /class="post /
0
 
0
     post_url = (page/".post:first/h2/a").attr("href")
0
 
0
@@ -58,7 +96,10 @@ class Chyrp < Test::Unit::TestCase
0
     resp, page = test_index
0
     page = Hpricot(page)
0
 
0
-    page_url = (page/"#sidebar/ul:nth(0)/li:nth(0)/a").attr("href")
0
+    first_page = (page/"#sidebar/ul:nth(0)/li:nth(0)/a")
0
+    return unless first_page
0
+
0
+    page_url = first_page.attr("href")
0
 
0
     get page_url
0
   end
0
@@ -125,6 +166,7 @@ class Chyrp < Test::Unit::TestCase
0
 
0
   def test_pagination
0
     resp, page = get("/page/2/")
0
+    return unless page =~ /class="post /
0
     assert_match /Page 2 of /, page, "No pagination links displayed."
0
   end
0
 
0
@@ -174,33 +216,16 @@ class Chyrp < Test::Unit::TestCase
0
     end
0
 
0
     def form_fuzz form
0
-      data = {}
0
+      data = form_get form
0
 
0
       (form/"*[@name]").each do |field|
0
-        if field['type'] == "hidden" or (field.name != "textarea" and field['value'] != "") or (field.name == "textarea" and !field.empty?)
0
-          if field.name == "select"
0
-            selected = (field/"option[@selected]")
0
-            option = selected.length > 0 ? selected : (field/"option:nth(0)")
0
-            data[field['name']] = option.attr("value")
0
-          elsif field.name != "button"
0
-            if field['type'] == "checkbox"
0
-              data[field['name']] = (field['checked'] || "no") == "checked" ? "1" : "0"
0
-            else
0
-              data[field['name']] = field['value'] || field.html
0
-            end
0
-          end
0
-          next
0
-        end
0
+        next unless data[field['name']].nil? or data[field['name']].empty?
0
 
0
         if field.name == "textarea"
0
           data[field['name']] = FUZZER[:textarea]
0
         elsif field.name == "input"
0
-          next if field['name'] == "trackbacks"
0
-          if field['name'] == "slug"
0
-            data[field['name']] = "test-slug"
0
-          else
0
-            data[field['name']] = FUZZER[:text]
0
-          end
0
+          next if field['type'] != "text" or field['name'] == "trackbacks" or field['name'] == "slug"
0
+          data[field['name']] = FUZZER[:text]
0
         end
0
       end
0
 

Comments