aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Chabowski <kevin@kch42.de>2011-11-09 23:31:45 +0100
committerKevin Chabowski <kevin@kch42.de>2011-11-09 23:31:45 +0100
commit37ae61fe6d76f72e4bd5567256ee4dd494649dab (patch)
tree14cd58a614a818bc1990968f9fb0eac695e6ea9b
parent11515220f3e47ac11e9239b358aceca1ee2e7269 (diff)
downloadratatoeskr-cms-37ae61fe6d76f72e4bd5567256ee4dd494649dab.tar.gz
ratatoeskr-cms-37ae61fe6d76f72e4bd5567256ee4dd494649dab.tar.bz2
ratatoeskr-cms-37ae61fe6d76f72e4bd5567256ee4dd494649dab.zip
Hooray! First backend function implemented (content/write)!
And it only took over a month. That's what I call efficiency.... NOT!
-rw-r--r--ratatoeskr/backend/main.php240
-rw-r--r--ratatoeskr/cms_style/layout.css32
-rw-r--r--ratatoeskr/templates/src/systemtemplates/content_write.html159
-rw-r--r--ratatoeskr/translations/en.php12
4 files changed, 423 insertions, 20 deletions
diff --git a/ratatoeskr/backend/main.php b/ratatoeskr/backend/main.php
index 9767cb4..737ffab 100644
--- a/ratatoeskr/backend/main.php
+++ b/ratatoeskr/backend/main.php
@@ -11,16 +11,44 @@
require_once(dirname(__FILE__) . "/../sys/models.php");
require_once(dirname(__FILE__) . "/../sys/pwhash.php");
+require_once(dirname(__FILE__) . "/../sys/textprocessors.php");
+require_once(dirname(__FILE__) . "/../languages.php");
$admin_grp = Group::by_name("admins");
+/* Mass creation of tags. */
+function maketags($tagnames, $lang)
+{
+ $rv = array();
+ foreach($tagnames as $tagname)
+ {
+ if(empty($tagname))
+ continue;
+ try
+ {
+ $tag = Tag::by_name($tagname);
+ }
+ catch(DoesNotExistError $e)
+ {
+ $tag = Tag::create($tagname);
+ $tag->title[$lang] = new Translation($tagname, "");
+ }
+ $rv[] = $tag;
+ }
+ return $rv;
+}
+
$backend_subactions = url_action_subactions(array(
"_index" => url_action_alias(array("login")),
"index" => url_action_alias(array("login")),
- /* _prelude guarantees that the user is logged in properly, so we do not have to care about that later. */
+ /* _prelude guarantees that the user is logged in properly, so we do not have to care about that later, and sets some STE vars. */
"_prelude" => function(&$data, $url_now, &$url_next)
{
- global $ratatoeskr_settings, $admin_grp, $ste;
+ global $ratatoeskr_settings, $admin_grp, $ste, $languages;
+
+ $ste->vars["all_languages"] = array();
+ foreach($languages as $code => $data)
+ $ste->vars["all_languages"][$code] = $data["language"];
/* Check authentification */
if(isset($_SESSION["ratatoeskr_uid"]))
@@ -40,7 +68,8 @@ $backend_subactions = url_action_subactions(array(
if($url_next[0] == "login")
$url_next = array("content", "write");
$data["user"] = $user;
- $ste->vars["user"] = array("name" => $user->username);
+ $ste->vars["user"] = array("name" => $user->username, "lang" => $user->language);
+
return; /* Authentification successful, continue */
}
else
@@ -67,18 +96,20 @@ $backend_subactions = url_action_subactions(array(
throw new Exception();
if(!$user->member_of($admin_grp))
throw new Exception();
+
+ /* Login successful. */
$_SESSION["ratatoeskr_uid"] = $user->get_id();
$_SESSION["ratatoeskr_pwhash"] = $user->pwhash;
+ $data["user"] = $user;
+ $ste->vars["user"] = array("name" => $user->username, "lang" => $user->language);
}
catch(Exception $e)
{
$ste->vars["login_failed"] = True;
}
- /* Login successful. */
- $data["user"] = $user;
- $ste->vars["user"] = array("name" => $user->username);
- throw new Redirect(array("content", "write"));
+ if(isset($data["user"]))
+ throw new Redirect(array("content", "write"));
}
echo $ste->exectemplate("systemtemplates/backend_login.html");
@@ -93,21 +124,212 @@ $backend_subactions = url_action_subactions(array(
"content" => url_action_subactions(array(
"write" => function(&$data, $url_now, &$url_next)
{
- global $ste, $translation;
+ global $ste, $translation, $textprocessors, $ratatoeskr_settings, $languages;
+
+ list($article, $editlang) = array_slice($url_next, 0);
+ if(!isset($editlang))
+ $editlang = $data["user"]->language;
+ if(isset($article))
+ $ste->vars["article_editurl"] = urlencode($article) . "/" . urlencode($editlang);
+ else
+ $ste->vars["article_editurl"] = "";
- $article = array_slice($url_next, 0);
$url_next = array();
+ $default_section = Section::by_id($ratatoeskr_settings["default_section"]);
+
$ste->vars["section"] = "content";
$ste->vars["submenu"] = "newarticle";
+ $ste->vars["textprocessors"] = array();
+ foreach($textprocessors as $txtproc => $properties)
+ if($properties[1])
+ $ste->vars["textprocessors"][] = $txtproc;
+
+ $ste->vars["sections"] = array();
+ foreach(Section::all() as $section)
+ $ste->vars["sections"][] = $section->name;
+ $ste->vars["article_section"] = $default_section->name;
+
+ /* Check Form */
+ $fail_reasons = array();
+
+ $inputs = array(
+ "date" => time(),
+ "article_status" => ARTICLE_STATUS_LIVE
+ );
+
+ if(isset($_POST["save_article"]))
+ {
+ if(!preg_match('/^[a-zA-Z0-9-_]+$/', @$_POST["urlname"]))
+ $fail_reasons[] = $translation["invalid_urlname"];
+ else
+ $inputs["urlname"] = $_POST["urlname"];
+ if((@$_POST["article_status"] < 0) or (@$_POST["article_status"] > 3))
+ $fail_reasons[] = $translation["invalid_article_status"];
+ else
+ $inputs["article_status"] = (int) $_POST["article_status"];
+ if(!isset($textprocessors[@$_POST["content_txtproc"]]))
+ $fail_reasons[] = $translation["unknown_txtproc"];
+ else
+ $inputs["content_txtproc"] = $_POST["content_txtproc"];
+ if(!isset($textprocessors[@$_POST["excerpt_txtproc"]]))
+ $fail_reasons[] = $translation["unknown_txtproc"];
+ else
+ $inputs["excerpt_txtproc"] = $_POST["excerpt_txtproc"];
+ if(!empty($_POST["date"]))
+ {
+ if(($time_tmp = strptime(@$_POST["date"], "%Y-%m-%d %H:%M:%S")) === False)
+ $fail_reasons[] = $translation["invalid_date"];
+ else
+ $inputs["date"] = @mktime($time_tmp["tm_sec"], $time_tmp["tm_min"], $time_tmp["tm_hour"], $time_tmp["tm_mon"] + 1, $time_tmp["tm_mday"], $time_tmp["tm_year"] + 1900);
+ }
+ else
+ $inputs["date"] = time();
+ $inputs["allow_comments"] = !(empty($_POST["allow_comments"]) or $_POST["allow_comments"] != "yes");
+
+ try
+ {
+ $inputs["section"] = Section::by_name($_POST["section"]);
+ }
+ catch(DoesNotExistError $e)
+ {
+ $fail_reasons[] = $translation["unknown_section"];
+ }
+
+ $inputs["title"] = $_POST["title"];
+ $inputs["content"] = $_POST["content"];
+ $inputs["excerpt"] = $_POST["excerpt"];
+ $inputs["tags"] = array_filter(array_map("trim", explode(",", $_POST["tags"])), function($t) { return !empty($t); });
+ if(isset($_POST["saveaslang"]))
+ $editlang = $_POST["saveaslang"];
+ }
+
+ function fill_article(&$article, $inputs, $editlang)
+ {
+ $article->urlname = $inputs["urlname"];
+ $article->status = $inputs["article_status"];
+ $article->timestamp = $inputs["date"];
+ $article->section = $inputs["section"];
+ $article->tags = maketags($inputs["tags"], $editlang);
+ $article->title [$editlang] = new Translation($inputs["title"], "" );
+ $article->text [$editlang] = new Translation($inputs["content"], $inputs["content_txtproc"]);
+ $article->excerpt[$editlang] = new Translation($inputs["excerpt"], $inputs["excerpt_txtproc"]);
+ }
+
if(empty($article))
{
/* New Article */
$ste->vars["pagetitle"] = $translation["new_article"];
+
+ if(empty($fail_reasons) and isset($_POST["save_article"]))
+ {
+ $article = Article::create($inputs["urlname"]);
+ fill_article($article, $inputs, $editlang);
+ try
+ {
+ $article->save();
+ $ste->vars["article_editurl"] = urlencode($article->urlname) . "/" . urlencode($editlang);
+ $ste->vars["success"] = htmlesc($translation["article_save_success"]);
+ }
+ catch(AlreadyExistsError $e)
+ {
+ $fail_reasons[] = $translation["article_name_already_in_use"];
+ }
+ }
+ }
+ else
+ {
+ try
+ {
+ $article = Article::by_urlname($article);
+ }
+ catch(DoesNotExistError $e)
+ {
+ throw new NotFoundError();
+ }
+
+ if(empty($fail_reasons) and isset($_POST["save_article"]))
+ {
+ fill_article($article, $inputs, $editlang);
+ try
+ {
+ $article->save();
+ $ste->vars["article_editurl"] = urlencode($article->urlname) . "/" . urlencode($editlang);
+ $ste->vars["success"] = htmlesc($translation["article_save_success"]);
+ }
+ catch(AlreadyExistsError $e)
+ {
+ $fail_reasons[] = $translation["article_name_already_in_use"];
+ }
+ }
+
+ foreach(array(
+ "urlname" => "urlname",
+ "section" => "article_section",
+ "status" => "article_status",
+ "timestamp" => "date",
+ "allow_comments" => "allow_comments"
+ ) as $prop => $k_out)
+ {
+ if(!isset($inputs[$k_out]))
+ $inputs[$k_out] = $article->$prop;
+ }
+ if(!isset($inputs["title"]))
+ $inputs["title"] = $article->title[$editlang]->text;
+ if(!isset($inputs["content"]))
+ {
+ $translation_obj = $article->text[$editlang];
+ $inputs["content"] = $translation_obj->text;
+ $inputs["content_txtproc"] = $translation_obj->texttype;
+ }
+ if(!isset($inputs["excerpt"]))
+ {
+ $translation_obj = $article->excerpt[$editlang];
+ $inputs["excerpt"] = $translation_obj->text;
+ $inputs["excerpt_txtproc"] = $translation_obj->texttype;
+ }
+ if(!isset($inputs["tags"]))
+ $inputs["tags"] = array_map(function($tag) use ($editlang) { return $tag->name; }, $article->tags);
+ $ste->vars["morelangs"] = array();
+ $ste->vars["pagetitle"] = $article->title[$editlang]->text;
+ foreach($article->title as $lang => $_)
+ {
+ if($lang != $editlang)
+ $ste->vars["morelangs"][] = array("url" => urlencode($article->urlname) . "/$lang", "full" => "($lang) " . $languages[$lang]["language"]);
+ }
+ }
+
+ /* Push data back to template */
+ if(isset($inputs["tags"]))
+ $ste->vars["tags"] = implode(", ", $inputs["tags"]);
+ if(isset($inputs["article_section"]))
+ $ste->section["article_section"] = $inputs["article_section"]->name;
+ $ste->vars["editlang"] = $editlang;
+ foreach(array(
+ "urlname" => "urlname",
+ "article_status" => "article_status",
+ "title" => "title",
+ "content_txtproc" => "content_txtproc",
+ "content" => "content",
+ "excerpt_txtproc" => "excerpt_txtproc",
+ "excerpt" => "excerpt",
+ "date" => "date",
+ "allow_comments" => "allow_comments"
+ ) as $k_in => $k_out)
+ {
+ if(isset($inputs[$k_in]))
+ $ste->vars[$k_out] = $inputs[$k_in];
}
+ if(!empty($fail_reasons))
+ $ste->vars["failed"] = $fail_reasons;
+
echo $ste->exectemplate("systemtemplates/content_write.html");
+ },
+ "tags" => function(&$data, $url_now, &$url_next)
+ {
+
}
))
));
diff --git a/ratatoeskr/cms_style/layout.css b/ratatoeskr/cms_style/layout.css
index 42ea1bc..f206da6 100644
--- a/ratatoeskr/cms_style/layout.css
+++ b/ratatoeskr/cms_style/layout.css
@@ -111,7 +111,7 @@ h1 {
min-width: 300px;
}
-code, code pre {
+code, code pre, code * {
font-family: monospace;
background: #eee;
}
@@ -150,7 +150,33 @@ h2 {
clear: both;
}
-form.fullwidthinputs input[type="text"], form.fullwidthinputs input[type="password"], form.fullwidthinputs select, form.fullwidthinputs textarea {
+.fullwidth {
width: 100%;
- margin:0mm;
+}
+
+div.error {
+ border: 1px solid #f00;
+ background: #fcc;
+ color: #f00;
+ padding: 1em;
+ margin: 3mm 0mm 3mm;
+ text-align: center;
+}
+
+div.notice {
+ border: 1px solid #33f;
+ background: #ccf;
+ color: #33f;
+ padding: 1em;
+ margin: 3mm 0mm 3mm;
+ text-align: center;
+}
+
+div.success {
+ border: 1px solid #0a0;
+ background: #cfc;
+ color: #0a0;
+ padding: 1em;
+ margin: 3mm 0mm 3mm;
+ text-align: center;
}
diff --git a/ratatoeskr/templates/src/systemtemplates/content_write.html b/ratatoeskr/templates/src/systemtemplates/content_write.html
index 962f116..81a4d9b 100644
--- a/ratatoeskr/templates/src/systemtemplates/content_write.html
+++ b/ratatoeskr/templates/src/systemtemplates/content_write.html
@@ -1,20 +1,165 @@
<ste:load name="master.html" />
+<ste:comment>Create textprocessor options. The default will be tags content.</ste:comment>
+<ste:mktag name="textprocessor_options">
+ <ste:set var="txtproc_default"><ste:tagcontent /></ste:set>
+ <ste:foreach array="textprocessors" value="txtproc">
+ <option value="<ste:escape>$txtproc</ste:escape>"?{~{$txtproc|eq|$txtproc_default}| selected="selected"|}><ste:escape>$txtproc</ste:escape></option>
+ </ste:foreach>
+</ste:mktag>
<ste:block name="content">
- <form action="$rel_path_to_root/content/write?{$article_editurl|/$article_editurl|}" method="POST" accept_charset="utf-8" class="fullwidthinputs">
+ <form action="$rel_path_to_root/backend/content/write/$article_editurl" method="POST" accept_charset="utf-8">
+ <ste:if>$failed
+ <ste:then>
+ <div class="error">
+ <p><strong><ste:get_translation for="article_edit_error" /></strong></p>
+ <ul>
+ <ste:foreach array="failed" value="v"><li>$v</li></ste:foreach>
+ </ul>
+ </div>
+ </ste:then>
+ </ste:if>
+ <ste:if>$success
+ <ste:then>
+ <div class="success">$success</div>
+ </ste:then>
+ </ste:if>
<div class="triplecolumns">
<div class="column_left">
<h2>Markdown Cheat Sheet</h2>
+
+ <h3>Emphasis / Strong</h3>
+ <p>
+ <code>*<em>emphasis</em>*</code><br />
+ <code>_<em>emphasis</em>_</code><br />
+ <code>**<strong>strong</strong>**</code><br />
+ <code>__<strong>strong</strong>__</code>
+ </p>
+
+ <h3>Paragraphs and manual line breaks.</h3>
+ <p>
+ <code>First Paragraph<br />
+<br />
+Second Paragraph with<br />
+long<br />
+text<br />
+<br />
+To enforce a line break&nbsp;&nbsp;<br />
+end a line with two whitespaces.</code>
+ </p>
+
+ <h3>Headers</h3>
+ <p>
+ <code>Header 1<br />
+========<br />
+<br />
+Header 2<br />
+--------<br />
+<br />
+# Header 1<br />
+<br />
+## Header 2<br />
+<br />
+...<br />
+<br />
+###### Header 6<br /></code>
+ </p>
+
+ <h3>Linking</h3>
+ <p>
+ <code>[Linktext](http://url/to/resource "Optional title")</code>
+ </p>
+ <p>
+ <code>[Linktext][id]. Somewhere else:<br />
+&nbsp;<br />
+ [id]: http://url/to/resource "Optional title"</code>
+ </p>
+
+ <h3>Images</h3>
+ <p>
+ <code>![alt text](/path/to/image "Optional title")</code>
+ </p>
+
+ <h3>Ordered / Unordered Lists</h3>
+ <p>
+ <code>* Item A<br />
+* Item B<br />
+&nbsp;&nbsp;<br />
+&nbsp;&nbsp;With a second paragraph.<br />
+&nbsp;<br />
+* Item C<br />
+&nbsp;&nbsp;* Item C1<br />
+&nbsp;&nbsp;* Item C2<br /></code>
+ </p>
+ <p>
+ <code>1. First element<br />
+2. Second Element
+</code>
+ </p>
+
+ <h3>Learn More</h3>
+ <p>
+ <a href="http://daringfireball.net/projects/markdown/syntax">Complete Syntax</a><br />
+ <a href="http://daringfireball.net/projects/markdown/dingus">Test Markdown</a>
+ </p>
</div>
+
<div class="column_right">
- <h2>Settings / Metadata</h2>
+ <h2><ste:get_translation for="settings_meta" /></h2>
- <p>Unique URL Title: <input type="text" name="urltitle" value="<ste:escape>$urltitle</ste:escape>" /></p>
- <p></p>
+ <p><ste:get_translation for="urlname" />: <input type="text" name="urlname" value="<ste:escape>$urlname</ste:escape>" class="fullwidth" /></p>
+ <p>
+ <ste:get_translation for="article_section" />:
+ <select name="section" class="fullwidth">
+ <ste:foreach array="sections" value="section_name">
+ <option name="<ste:escape>$section_name</ste:escape>"?{~{$section_name|eq|$article_section}| selected="selected"|}><ste:escape>$section_name</ste:escape></option>
+ </ste:foreach>
+ </select>
+ </p>
+ <p><ste:get_translation for="tags_cs" />: <input type="text" name="tags" value="<ste:escape>$tags</ste:escape>" class="fullwidth" /></p>
+ <p><ste:get_translation for="date_time" />:<br />(YYYY-MM-DD HH:MM:SS) <input type="text" name="date"?{$date| value="<ste:date timestamp='$date'>%Y-%m-%d %H:%M:%S</ste:date>"|} class="fullwidth" /></p>
+ <p>
+ <ste:get_translation for="article_status" />:
+ <ste:set var="article_status">?{$article_status|$article_status|1}</ste:set>
+ <select name="article_status" class="fullwidth">
+ <option value="0"?{~{$article_status|eq|0}| selected="selected"|}><ste:get_translation for="article_status_hidden" /></option>
+ <option value="1"?{~{$article_status|eq|1}| selected="selected"|}><ste:get_translation for="article_status_live" /></option>
+ <option value="2"?{~{$article_status|eq|2}| selected="selected"|}><ste:get_translation for="article_status_sticky" /></option>
+ </select>
+ </p>
+ <p><ste:get_translation for="allow_comments" />: <input type="checkbox" name="allow_comments" value="yes" ?{$allow_comments|checked="checked" |}/></p>
</div>
+
<div class="column_main">
- <p><ste:get_translation for="articleedit_title" />: <input type="text" name="title" value="<ste:escape>$title</ste:escape>" /></p>
- <p><ste:get_translation for="articleedit_content" />: <textarea name="content" cols="80" rows="20"><ste:escape>$content</ste:escape></textarea></p>
- <p><ste:get_translation for="articleedit_excerpt" />: <textarea name="excerpt" cols="80" rows="10"><ste:escape>$excerpt</ste:escape></textarea></p>
+ <ste:if>$morelangs
+ <ste:then>
+ <h2><ste:get_translation for="article_other_languages" /></h2>
+ <p>
+ <ste:foreach array="morelangs" value="lang" counter="i">
+ ?{~{$i|eq|0}|| - }<a href="$rel_path_to_root/backend/content/write/$lang[url]"><ste:escape>$lang[full]</ste:escape></a>
+ </ste:foreach>
+ </p>
+ </ste:then></ste:if>
+ <p>
+ <ste:get_translation for="articleedit_title" />:
+ <input type="text" name="title" value="<ste:escape>$title</ste:escape>" class="fullwidth" />
+ </p>
+ <p>
+ <ste:get_translation for="articleedit_content" />: <select name="content_txtproc"><ste:textprocessor_options>$content_txtproc</ste:textprocessor_options></select>
+ <textarea name="content" cols="80" rows="20" class="fullwidth"><ste:escape>$content</ste:escape></textarea>
+ </p>
+ <p>
+ <ste:get_translation for="articleedit_excerpt" />: <select name="excerpt_txtproc"><ste:textprocessor_options>$excerpt_txtproc</ste:textprocessor_options></select>
+ <textarea name="excerpt" cols="80" rows="10" class="fullwidth"><ste:escape>$excerpt</ste:escape></textarea>
+ </p>
+ <p style="text-align: center;">
+ <ste:get_translation for="save_texts_as_lang" />: <select name="saveaslang">
+ <ste:set var="default_langsel">?{$editlang|$editlang|$user[lang]}</ste:set>
+ <ste:foreach array="all_languages" key="code" value="name">
+ <option value="$code"?{~{$default_langsel|eq|$code}| selected="selected"|}>($code) $name</option>
+ </ste:foreach>
+ </select><br />
+ <input type="submit" name="save_article" />
+ </p>
</div>
</div>
<div class="triplecolumns_stop"></div>
diff --git a/ratatoeskr/translations/en.php b/ratatoeskr/translations/en.php
index c80e92d..31d0944 100644
--- a/ratatoeskr/translations/en.php
+++ b/ratatoeskr/translations/en.php
@@ -50,7 +50,17 @@ $translation = array(
"article_status" => "Article Status",
"article_status_hidden" => "Hidden",
"article_status_live" => "Live",
- "article_status_sticky" => "Sticky"
+ "article_status_sticky" => "Sticky",
+ "article_section" => "Section",
+ "invalid_urlname" => "Invalid URL name (Can contain a-z A-Z 0-9 - and _)",
+ "invalid_article_status" => "Invalid article status",
+ "unknown_txtproc" => "Unknown Textprocessor",
+ "invalid_date" => "Invalid date",
+ "article_edit_error" => "Could not edit article.",
+ "unknown_section" => "Unknown section",
+ "allow_comments" => "Allow comments?",
+ "article_name_already_in_use" => "Article name is already in use.",
+ "article_save_success" => "Article successfully saved."
);
?>