<h3>{{ _("Compose new entry") }}</h3>
<form name="entry" method="post">
{{ xsrf_form_html() }}
- <input type="hidden" name="id" value="{{ entry.id }}">
+ {% if entry.id %}
+ <input type="hidden" name="id" value="{{ entry.id }}">
+ {% end %}
<table>
<tr>
{% if lang == "de" %}
<p>
Auf dieser Seite können Sie <strong>kostenlos</strong> die neueste
- Version von IPFire herunterladen. Ältere Versionen oder
- andere Downloadoptionen finden Sie weiter unten auf der Seite.
+ Version von IPFire herunterladen.
</p>
-
<p>
- IPFire ist innerhalb von 15 bis 20 Minuten eingerichtet.
- Eine <a href="http://wiki.ipfire.org/{{ lang }}/installation/start"
- target="_blank">Installationsanleitung</a>
- ist in unserem Wiki zu finden.
+ Ältere Versionen oder andere Downloadoptionen finden Sie im
+ <a href="http://downloads.ipfire.org/">Download Center</a>.
</p>
{% else %}
<p>
On this page one can download the latest version of IPFire
- <strong>for free</strong>. Older versions and other downloads
- can be retrieved on the linked pages below.
+ <strong>for free</strong>.
</p>
-
- <!-- <p>
- IPFire can be installed within 15 to 20 minutes. An
- <a href="http://wiki.ipfire.org/{{ lang }}/installation/start"
- target="_blank">installation guide</a> can be found on our wiki.
- </p> -->
-
<p>
- Some other things you might be interested in as well:
+ Older versions and other downloads can be found in the
+ <a href="http://downloads.ipfire.org/">Download Center</a>.
</p>
- <ul>
- <li>
- <a href="http://wiki.ipfire.org/{{ lang }}/installation/start">{{ _("Installation guide") }}</a>
- </li>
- </ul>
{% end %}
-
- <p>
- Older downloads can be found in the
- <a href="http://downloads.ipfire.org/">Download Center</a>.
- </p>
<br class="clear" />
<br class="clear" />
<h3>{{ _("Donation") }}</h3>
- <p>
- If you like IPFire, there is the opportunity to donate a small amount
- of money to the project. This will help the people that are running
- this project very much.
- </p>
- <p>
- <div align="center">
- <form action="https://www.paypal.com/cgi-bin/webscr" method="post">
- <input type="hidden" name="cmd" value="_s-xclick">
- <input type="hidden" name="hosted_button_id" value="10781833">
- <input type="image" src="https://www.paypal.com/de_DE/DE/i/btn/btn_donateCC_LG.gif"
- border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
- <img alt="" border="0" src="https://www.paypal.com/de_DE/i/scr/pixel.gif" width="1" height="1">
- </form>
- </div>
+ {% if lang == "de" %}
+ <p>
+ Wenn Ihnen IPFire gefällt, gibt es die Möglichkeit mit einer kleinen
+ Menge Geld das Projekt zu unetrstützen. Diese Unterstützung bedeutet
+ sehr viel, denn sie hilft das Projekt fortzuführen.
+ </p>
<br class="clear" />
- </p>
- <p>
- If you want to know more about how you can help the IPFire project
- read <a href="/donation">this</a>.
- </p>
+ <p>
+ <div align="center">
+ <form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+ <input type="hidden" name="cmd" value="_s-xclick">
+ <input type="hidden" name="hosted_button_id" value="10781833">
+ <input type="image" src="https://www.paypal.com/de_DE/DE/i/btn/btn_donateCC_LG.gif"
+ border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
+ <img alt="" border="0" src="https://www.paypal.com/de_DE/i/scr/pixel.gif" width="1" height="1">
+ </form>
+ </div>
+ </p>
+ <br class="clear" />
+ <p>
+ Um mehr darüber zu erfahren, wie Sie das Projekt unterstützen können,
+ klicken Sie <a href="/donation">hier</a>.
+ </p>
+ {% else %}
+ <p>
+ If you like IPFire, there is the opportunity to donate a small amount
+ of money to the project. This will help the people that are running
+ this project very much.
+ </p>
+ <br class="clear" />
+ <p>
+ <div align="center">
+ <form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+ <input type="hidden" name="cmd" value="_s-xclick">
+ <input type="hidden" name="hosted_button_id" value="10781833">
+ <input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif"
+ border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
+ <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
+ </form>
+ </div>
+ </p>
+ <br class="clear" />
+ <p>
+ If you want to know more about how you can help the IPFire project
+ read <a href="/donation">this</a>.
+ </p>
+ {% end %}
{% end block %}
{% block sidebar %}
in mittleren bis kleinen Unternehmensnetzwerken und Heimnetzwerken.
</p>
<p>
- Obwohl das System extrem schlank gehalten und gehärtet wurde und können
+ Obwohl das System extrem schlank gehalten und gehärtet wurde, können
Addons mit nur einem Klick installiert werden. Diese Eigenschaft unterscheidet
IPFire von anderen Distributionen: IPFire ist einfach zu administrieren
aber hat genug Leistung allen Anforderungen gewachsen zu sein.
<br class="clear" />
- <p>
+ <h4>
{{ _("See what makes IPFire so great:") }}
- </p>
+ </h4>
<table class="blocks">
<tr>
{% if lang == "de" %}
<p>
Die oberste Priorität ist die Sicherheit des Systems.
- So werden zum Beispiel Sicherheitsupdates zügig zur
- Verfügung gestellt.
+ Zum Beispiel werden Sicherheits- updates regelmäßig und
+ zügig verteilt.
</p>
{% else %}
<p>
As the most important issue: Security updates
- are deployed regularly and in a timely manner.
+ are deployed regularly and promptly.
</p>
{% end %}
<a href="/about#security">{{ _("Learn more.") }}</a>
<span>{{ _("Flexibility") }}</span>
{% if lang == "de" %}
<p>
- Heutzutage ist nichts wichtiger als flexibel zu sein
+ Heutzutage ist es auch wichtig flexibel zu sein
und sich der Welt anzupassen. Genau wie IPFire...
</p>
{% else %}
{% else %}
<p>
The success of IPFire is based on the community that
- is working on the code an spreading IPFire to the world.
+ is working on the code and spreading IPFire to the world.
</p>
{% end %}
<p>
<p class="links">
{{ _("Quick links") }} •
<a href="/about">{{ _("About IPFire") }}</a>
- •
- <a href="/screenshots">{{ _("Screenshots") }}</a>
+ <!-- •
+ <a href="/about">{{ _("Screenshots") }}</a> -->
</p>
- <br class="clear" />
+ <div class="line"></div>
{% for item in latest_news %}
{{ modules.NewsItem(item) }}
</p>
-->
</div>
-
+
+ <div class="line"></div>
+
{% for entry in entries %}
{{ modules.PlanetEntry(entry, short=True) }}
{% end %}
{% block sidebar %}
<h4>{{ _("People on the planet") }}</h4>
- <ul>
+ <ul class="list">
{% for author in authors %}
<li>
<a href="/user/{{ author.uid }}">{{ author.cn }}</a>
"Virtualization","Virtualisierung"
"It's free","IPFire ist frei"
"Packet management","Paketmanagement"
+"Really important guides are:","Empfehlenswerte Artikel sind:"
+"Installation guide","Installationsanleitung"
+"Learn how to start.","Wie fängt man an?"
+"Server","Server"
+"Channel","Channel"
+"Getting support","Support"
+"Concept of the system","Konzept"
+"Hardware section on the wiki","Hardware-Sektion im Wiki"
+"Hardware compatibility list","Hardwarekompatibilitätsliste"
+"networking","Netzwerk"
+
self.add_handlers(r"planet\.ipfire\.org", [
(r"/", PlanetMainHandler),
(r"/post/([A-Za-z0-9_-]+)", PlanetPostingHandler),
- (r"/user/([a-z0-9]+)", PlanetUserHandler),
+ (r"/user/([a-z0-9_-]+)", PlanetUserHandler),
] + static_handlers)
# stasy.ipfire.org
from mirrors import Mirrors
from netboot import NetBoot
from news import News
-from planet import Planet
+from planet import Planet, PlanetEntry
from releases import Releases
from settings import Settings as Config
from stasy import Stasy
import hashlib
import ldap
+import logging
import urllib
from misc import Singleton
class Accounts(object):
__metaclass__ = Singleton
+ @property
+ def settings(self):
+ return Settings()
+
def __init__(self):
self.__db = None
@property
def db(self):
if not self.__db:
- ldap_uri = Settings().get("ldap_uri")
+ ldap_uri = self.settings.get("ldap_uri")
self.__db = ldap.initialize(ldap_uri)
- bind_dn = Settings().get("ldap_bind_dn")
+ bind_dn = self.settings.get("ldap_bind_dn")
+
if bind_dn:
- bind_pw = Settings().get("ldap_bind_pw")
+ bind_pw = self.settings.get("ldap_bind_pw")
self.__db.simple_bind(bind_dn, bind_pw)
#!/usr/bin/python
+import re
import textile
+import tornado.database
+import unicodedata
from accounts import Accounts
from databases import Databases
from misc import Singleton
class PlanetEntry(object):
- def __init__(self, entry):
- self.__entry = entry
+ def __init__(self, entry=None):
+ if entry:
+ self.__entry = entry
+ else:
+ self.__entry = tornado.database.Row({
+ "id" : None,
+ "title" : "",
+ "markdown" : "",
+ })
+
+ def set(self, key, val):
+ self.__entry[key] = val
+
+ @property
+ def planet(self):
+ return Planet()
@property
def id(self):
return self.render(self.markdown, 400)
def render(self, text, limit=0):
- if limit and len(text) >= limit:
- text = text[:limit] + "..."
- return textile.textile(text)
+ return self.planet.render(text, limit)
@property
def text(self):
if author:
authors.append(author)
- return authors
+ return sorted(authors)
def get_entry_by_slug(self, slug):
entry = self.db.get("SELECT * FROM planet WHERE slug = %s", slug)
if entry:
return PlanetEntry(entry)
+ def get_entry_by_id(self, id):
+ entry = self.db.get("SELECT * FROM planet WHERE id = %s", id)
+ if entry:
+ return PlanetEntry(entry)
+
def _limit_and_offset_query(self, limit=None, offset=None):
query = " "
# Respect limit and offset
query += self._limit_and_offset_query(limit=limit, offset=offset)
-
entries = self.db.query(query)
return [PlanetEntry(e) for e in entries]
+
+ def render(self, text, limit=0):
+ if limit and len(text) >= limit:
+ text = text[:limit] + "..."
+ return textile.textile(text)
+
+ def _generate_slug(self, title):
+ slug = unicodedata.normalize("NFKD", title).encode("ascii", "ignore")
+ slug = re.sub(r"[^\w]+", " ", slug)
+ slug = "-".join(slug.lower().strip().split())
+
+ if not slug:
+ slug = "entry"
+
+ while True:
+ e = self.db.get("SELECT * FROM planet WHERE slug = %s", slug)
+ if not e:
+ break
+ slug += "-"
+
+ return slug
+
+ def update_entry(self, entry):
+ self.db.execute("UPDATE planet SET title = %s, markdown = %s WHERE id = %s",
+ entry.title, entry.markdown, entry.id)
+
+ def save_entry(self, entry):
+ slug = self._generate_slug(entry.title)
+
+ self.db.execute("INSERT INTO planet(author_id, title, slug, markdown, published) "
+ "VALUES(%s, %s, %s, %s, UTC_TIMESTAMP())", entry.author.uid, entry.title,
+ slug, entry.markdown)
+
from handlers_base import *
+import backend
class AdminBaseHandler(BaseHandler):
+ @property
+ def accounts(self):
+ return backend.Accounts()
+
+ @property
+ def planet(self):
+ return backend.Planet()
+
def get_current_user(self):
return self.get_secure_cookie("account")
text = self.get_argument("text", "")
# Render markup
- self.write(markdown2.markdown(text))
+ self.write(self.planet.render(text))
self.finish()
class AdminPlanetHandler(AdminBaseHandler):
@tornado.web.authenticated
def get(self):
- entries = self.backend.db.planet.query("SELECT * FROM planet ORDER BY published DESC")
-
- for entry in entries:
- entry.author = self.backend.accounts.search(entry.author_id)
+ entries = self.planet.get_entries(limit=100)
self.render("admin-planet.html", entries=entries)
class AdminPlanetComposeHandler(AdminBaseHandler):
@tornado.web.authenticated
def get(self, id=None):
+ entry = backend.PlanetEntry()
+
if id:
- entry = self.backend.db.planet.get("SELECT * FROM planet WHERE id = '%s'", int(id))
- else:
- entry = tornado.database.Row(id="", title="", markdown="")
+ entry = self.planet.get_entry_by_id(id)
self.render("admin-planet-compose.html", entry=entry)
@tornado.web.authenticated
def post(self, id=None):
id = self.get_argument("id", id)
- title = self.get_argument("title")
- markdown = self.get_argument("markdown")
- author = self.backend.accounts.search(self.current_user)
- if id:
- entry = self.backend.db.planet.get("SELECT * FROM planet WHERE id = %s", id)
- if not entry:
- raise tornado.web.HTTPError(404)
+ entry = backend.PlanetEntry()
- self.backend.db.planet.execute("UPDATE planet SET title = %s, markdown = %s "
- "WHERE id = %s", title, markdown, id)
+ if id:
+ entry = self.planet.get_entry_by_id(id)
- slug = entry.slug
+ entry.set("title", self.get_argument("title"))
+ entry.set("markdown", self.get_argument("markdown"))
+ entry.set("author_id", self.current_user)
+ if id:
+ self.planet.update_entry(entry)
else:
- slug = unicodedata.normalize("NFKD", title).encode("ascii", "ignore")
- slug = re.sub(r"[^\w]+", " ", slug)
- slug = "-".join(slug.lower().strip().split())
-
- if not slug:
- slug = "entry"
-
- while True:
- e = self.backend.db.planet.get("SELECT * FROM planet WHERE slug = %s", slug)
- if not e:
- break
- slug += "-"
-
- self.backend.db.planet.execute("INSERT INTO planet(author_id, title, slug, markdown, published) "
- "VALUES(%s, %s, %s, %s, UTC_TIMESTAMP())", author.uid, title, slug, markdown)
+ self.planet.save_entry(entry)
self.redirect("/planet")
class AdminAccountsBaseHandler(AdminBaseHandler):
- @property
- def accounts(self):
- return self.backend.accounts
+ pass
class AdminAccountsHandler(AdminAccountsBaseHandler):
@tornado.web.authenticated
def get(self):
- accounts = self.backend.accounts.list()
+ accounts = self.accounts.list()
self.render("admin-accounts.html", accounts=accounts)
class AdminMirrorsBaseHandler(AdminBaseHandler):
- @property
- def db(self):
- return self.backend.db.mirrors
-
@property
def mirrors(self):
- return self.backend.mirrors
+ return backend.Mirrors()
class AdminMirrorsHandler(AdminMirrorsBaseHandler):