Direkt zum Inhalt | Direkt zur Navigation

Benutzerspezifische Werkzeuge
Anmelden
Sektionen
Sie sind hier: Startseite Blog

[CodeLog] flaschenpost 002: Autorisierung, Blog hinzufügen

Heute gibt es einige, kleine Änderungen an Bestehende, sowie das implementieren einer Funktion, die überprüft ob man überhaupt authorisiert ist, eine bestimmte Seite zu betrachten. Des weiteren werden nun endlich die Blogs hinzugefügt.

Nächster Schritt zur eigenen Bloggingsoftware: Hinzufügen eines Blogs. Also eines überbegriffes unter dem man anschließend Nachrichten veröffentlichen möchte (wie zB mein "CodeLog" hier).

Vorher passe ich den Login ein wenig an: Bisher zeigte die login.html ungeachtet der Tatsache ob ich bereits eingeloggt bin oder nicht, einen login-prompt. Das habe ich nun geändert. Wenn man bereits angemeldet ist, zeigt er einem nur einen Link zum ausloggen an, welcher die Klassen "btn" und "btn-danger" hat. Dadurch sieht das ganze wie folgt aus:

Auch beim Loginbutton habe ich 2 weitere Klassen eingefügt: "btn" und "btn-success"

Weiter im Text mit dem Hinzufügen eines Blogs. Als erstes brauche ich für die View ein neues Template. Diese kann dank dem Layout wieder sehr schlank gehalten werden:

<!doctype html>
{% extends "layout.html" %}
{% block content %}
  <h1>Add a new Blog</h1>
  <form action="" method="post">
    <p>
      <h2>Blogtitle: </h2>
      <input type="text" name="blogtitle">
    </p>
    <p>
      <h2>Description:</h2>
      <small>
        The Description will be shown as a tooltip in the navbar, if you hover the Link.
      </small>
      <br/>
      <textarea rows="3" name="description"> </textarea>
    </p>
    <p>
      <input type="submit" value="Save" class="btn-success btn">
    </p>
  </form>
{% endblock %}

Und dann noche ine Funktion um dieses Template anzusprechen:

def add_blog():
    """
    """
    return render_template('add_blog.html')

Das reicht für's Erste.

Nun fehlt in der MongoDB eine neue Collection. Also blog.py angelegt und befüllt:

from mongokit import Document

class Blog(Document):
__collection__ = 'blog'
structure = {
'blog_name': str,
'description': str,
'blogid': str,
}
required_fields = ['blogtitle', 'blogid']
default_values = {'description': ""}
use_dot_notation = True

NextUp: Template ein wenig anpassen und die Funktion für die View. Die View soll natürlich nur als angemeldeter Nutzer zur Verfügung stehen, also einfach eine Bedingung um das Form und anschließend (da ich es vermutlich öfter brauchn werde) eine Funktion schreiben und in die utils.py packen.

from flask import render_template, flash

[...]

def check_authorization(session):
"""
"""
if session.get('username', None):
user_col = DatabaseHelper.get_collection('users')
username = session.get('username', None)
user = user_col.find_one({'login_name':username}) or user_col.find_one({'username':username})
if user:
return True
flash('You are not authorized to view this page.', category='error')
return False

Ich checke hier nur ob in der Nutzer, der in der Session steht, auch wirklich existiert. Das ist nicht sicher! Dieser Punkt kommt auf meine ToDo. Das Template und die Viewfunktionen sehen nun so aus:

<!doctype html>
{% extends "layout.html" %}
{% block content %}
{% if authorized %}
<h1>Add a new Blog</h1>
<form action="" method="post">
<p>
<h2>Blogtitle: </h2>
<input type="text" name="blogtitle" required="required">
</p>
<p>
<h2>Description:</h2>
<small>
The Description will be shown as a tooltip in the navbar, if you hover the Link.
</small>
<br/>
<textarea rows="3" name="description"> </textarea>
</p>
<p>
<input type="submit" value="Save" class="btn-success btn">
</p>
</form>
{% endif %}
{% endblock %}

und ...

def add_blog():
"""
"""
if check_authorization(session):
return render_template('add_blog.html', authorized=True)
else:
return render_template('add_blog.html', authorized=False)

Und als Screenshot:

Der Blog muss ja nun auch wirklich hinzugefügt werden. Dazu nochmal ran an die add.py

from urllib import quote

[...]

def add_blog():
"""
"""
if check_authorization(session):
if request.method == 'POST':
blog_col = DatabaseHelper.get_collection('blogs')
blogtitle = request.form.get('blogtitle')
blogid = quote(blogtitle.lower())
description = request.form.get('description')
if blog_col.find_one({'blogtitle' : blogtitle}):
flash("The Blog " + blogtitle + " could not be created. A Blog with this title allready exists.",
category="warning")
return render_template('add_blog.html', authorized=True)
new_blog = blog_col.Blog()
new_blog['blogid'] = blogid
new_blog['blogtitle'] = blogtitle
if not description == u' ':
new_blog['description'] = description
new_blog.save()
flash("The Blog " + blogtitle + " was successfully created.",
category="success")
return redirect(url_for('index'))
else:
return render_template('add_blog.html', authorized=True)
else:
return render_template('add_blog.html', authorized=False)

Fehlt nur noch die Blogs in die Navbar einfügen. Das Ganze ist ein wenig tricky. Erstmal brauche ich eine Funktion, die mir alle Blogs zurück gibt UND im Template erreichbar ist. Über einen template_filter, wie ihn flask anbietet, geht es leider nicht zu realisieren. Also muss ich direkt ans Jinja ran. Folgende Funktion in die application.py:

def get_blogs():
blog_col = DatabaseHelper.get_collection('blogs')
blogs = blog_col.find()
return [blog for blog in blogs]

und zum verdraten noch:

app.jinja_env.globals['get_blogs'] = get_blogs

Das Template anpassen ist dann eine Kleinigkeit. Fix noch layout.html angepasst:

<ul class="nav">
<li class="divider-vertical"></li>
{% for blog in get_blogs() %}
<li>
<a href="#"
{% if blog['description'] %}
data-content="{{ blog['description'] }}"
rel="popover"
class="has_popover"
{% endif %}
>
{{ blog['blogtitle'] }}
</a>
</li>
{% endfor %}
</ul>

Und fertig für's Erste. Hier noch ein Screenshot (die Description des 3. Blogs, welche als Popover erscheint, ist leider nicht zu sehen. Eventuell mache ich später ein neues).

[CodeLog] flaschenpost 001: ein neues Template

Mein erster CodeLog-Eintrag.

Eine Musikplaylist ist zusammengestellt, Kaffee steht breit und was ich heute erledigen möchte weiß ich auch schon. Der erste Eintrag. Es kann los gehen.

Mein erster CodeLog soll über "flaschenpost" gehen. Ein kleines Projekt, welches ich vor einigen Monaten auf der RuPy in Poznań gestartet habe. Damals wollte ich mich eigentlich nur in das MicroFramework Flask und die NoSQL Datenbank MongoDB einarbeiten. Mein Anspruch war damals, ein schlanke und leicht bedienbare Blogginganwendung zu programmieren (ja... noch eine) doch leider ist das Projekt aus Zeitgründen ein wenig eingeschlafen. Die letzten 2-3 Wochen hatte ich recht viel um die Ohren und ich muss den Kopf ein wenig frei bekommen. Darum habe ich entschieden, mich jetzt wieder ran zu setzen und es ein wenig weiter zu machen.

Der aktuelle Stand ist nichts berauschendes. Es gibt eine Startseite und eine Möglichkeit sich ein- und auszuloggen. Auch das aktuelle Template kann sich mehr schlecht als recht so bezeichnen.

Genau dieses Template ist es, welches ich heute ein wenig anpassen möchte. Hier der aktuelle Stand:

Schlank ist das Template auf jeden Fall. Um das ganze ein wenig ansprechender zu gestalten, habe ich mir gedacht ich setze ein CSS Framework ein. Vor kurzem erst wurden mir 2 empfohlen: bootstrap und compass. Meine Wahl (oder eher die der Münze) fiel auf bootstrap, das CSS Framework von Twitter. Es scheint einige kleine Fehler zu haben, kommt aber sehr charmant daher.

Flask setzt als Templatingengine Jinja2 ein. Jinja2 erlaubt es, beim Erstellen von HTML Seiten Blöcke zu definieren. Andere Seiten können dann ein besetehendes Template „erweitern“ um so nur gezielt Blöcke zu überschreiben. Das macht mir die Aufgabe einfach: ich habe eine layout.html welche alle optischen Gegebenheiten der Webseite definiert. Darüber hinaus, kann ich ohne viel Aufwald die einzelnen Unterseiten erstellen. Die index.html sieht zum Beispiel wie folgt aus:

<!doctype html>
{% extends "layout.html" %}
{% block content %}

<h1>index</h1>
Hello world.
{% endblock %}

Das macht das Umstellen auf bootstrap sehr einfach, da ich nur die layout.html anpassen muss. Was also als erstes? Natürlich die alte CSS Datei entfernen:

$ git rm flaschenpost/static/style.css

und nachdem ich die neuen css und js files in den static Ordner gelegt habe wird in der layout.html aus

{% block styles %}
  {% if ownstyle_path %}
    <link rel="stylesheet" type="text/css" href={{ ownstyle_path }}>
  {% else %}
    <link rel="stylesheet" type="text/css" href={{ url_for('static', filename="style.css") }}>
  {% endif %}
{% endblock %}

eben noch

{% block styles %}
  {% if ownstyle_path %}
    <link rel="stylesheet" type="text/css" href={{ ownstyle_path }}>
  {% else %}

<link rel="stylesheet" type="text/css" href={{ url_for('static', filename="base.css") }}>
<link rel="stylesheet" type="text/css" href={{ url_for('static', filename="bootstrap.min.css") }}>
<script type="text/javascript" src={{ url_for('static', filename="jquery-1.7.1.min.js") }}></script>
<script type="text/javascript" src={{ url_for('static', filename="bootstrap.min.js") }}></script>
  {% endif %}
{% endblock %}

gemacht. Und was hab ich dadurch erreicht? Natürlich noch nicht viel:

Weiter geht’s: Die Basis CSS-Klassen einfügen, wie in der Doku beschrieben: dem äußersten div die Klasse „container“ hinzufügen, ein paar divs mit „row“ einfügen und sonnst ein paar span- und offset-Klassen. Was kommt bei rum? Werfen wir doch mal einen Blick auf die Login Page:

Es wird doch. Als nächstes die Infoboxen. In der login.py ändere ich in Zeile 24 …

flash('You are successfully logged in.', category='message')

zu …

flash('You are successfully logged in.', category='success')

und schon kann ich meine Nachrichten im Template folgendermaßen ausgeben:

{% for category, msg in get_flashed_messages(with_categories=true) %}
  <div class="row">
    <div class="span12">
      <div class="
alert alert-block alert-{{ category }} fade in">
        <a class="close" href="#" data-dismiss="alert">×</a>
        <strong>{{ msg }}</strong>
      </div>
    </div>
  </div>
{% endfor %}

Ergebnis:

Nun füge ich dem Footer und meinem Contentdiv die Klasse "well" hinzu. Als Letztes für heute baue ich mir eine neue Navbar, wo ich auch den Loginlink und ein Searchfeld für eine spätere Suche unter bringe. Das Navigation bauen erweißt sich im ersten Moment als ein wenig kniffelig aber die Bootstrap Doku ist verdammt gut. Links den Namen des Blogs (alternativ einfach nur "Blog"), daneben kommen dann die einzelnen Links zu den verschiedenen Blogs. Rechts die Suche und der Login. Ich bin ganz zufrieden damit:

Zu guter Letzt nur noch commit und ab ins GitRepo:

git commit -m "build whole new design, based on bootstrap" && git push

Coding Diary?

Nur eine Idee...

Seit ein paar Tagen habe ich die Idee, einen Blog übers Programmieren zu machen. Eigentlich nichts besonderes. Davon gibt es ja schon unzählige im Netz.

Ich werde über meine OpenSource Projekte schreiben und zwar mehr oder weniger genau dann, wärend ich an ihnen arbeite. Wir werden sehen, wie das klappt und wie es an kommt...

RESTful Webserivce

Im Rahmen des Seminares "Serverseitige Technologien" der Berufsakademie Leipzig entstandener Kurzvortrag zum Thema REST

Als Präsentation anzeigen...

Was ist REST oder RESTful?

  • steht für "Representational State Transfer" (im Deutschen oft "ressourcenorientierter Webservice" genannt)
  • erstmals in Roy Fieldings Dissertation "Architectural Styles and the Design of Network-based Software Architectures"
  • keine Norm und daher nur schwammig definiert
  • es gibt 5 Prinzipien nach Fielding (Adressierbarkeit, unterschiedliche Präsentation, Zustandslosigkeit, Operationen, Verwendung von Hypermedia)
  •  

    FUNFACT: Roy Fielding erlangte mit seiner Dissertation einen ,,Doctor of Philosophy'' in Computer Science

    Addressierbarkeit

     

  • Zugriffe auf Inhalte müssen eindeutig sein (über "Uniform Ressource Identifier" => URI)
  • Vorteil: URLs führen immer zu dem selben Ergebnis
  •  

    unterschiedliche Präsentation

     

  • unter einer URL können mehrere Repräsentationen des selben Inhaltes abgerufen werden (z.B.: HTML, JSON oder XML)
  • Vorteil: Mensch und Maschine können mit Informationen umgehen
  •  

    Zustandslosigkeit

     

  • jede Anfrage enthält alle nötigen Informationen
  • jede Anfrage ist in sich geschlossen
  • Vorteil: leichtes "caching" / Vorteile bei der Skalierbarkeit
  •  

    Operationen

     

  • nur HTTP konforme Operationen sind erlaubt (z.B.: GET, POST, PUT und DELETE)
  • GET muss "sicher" sein (nur Ausliefern von Informationen, kein bearbeiten)
  • Vorteil: Serververhalten ist "vorhersehbar"
  •  

    Verwendung von Hypermedia

     

  • "Verbindung" zusammenhängender Informationen (z.B. über Links)
  • Vorteil: REST-Clients können sich durch den Webservice "durchnavigieren"
  •  

    Quellen / weiterführende Links

     

  • Roy Fieldings Dissertations: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
  • Wikipedia (deutsch): http://de.wikipedia.org/wiki/Representational_State_Transfer
  • Wikipedia (englisch): http://en.wikipedia.org/wiki/Representational_state_transfer
  • Witzige kleine Geschichte, die REST einfach erklärt: http://d4dilip.wordpress.com/2011/10/18/how-i-explained-rest-to-my-wife/
  • Datalove

    No Copyright, no license. Sorry, no kitthes.

    The Priniciples of Datalove


    Love data

    Data is essential
    Data must flow
    Data must be used
    Data is neither good nor bad
    There is no illegal data
    Data is free
    Data can not be owned
    No man, machine or system shall interrupt the flow of data
    Locking data is a crime against datanity

    Love data

     

    No Copyright, no license. Sorry, no kitthes.

    Nostalgie und Melancholie - der Treibsand unserer Zeit

    Wieder und wieder werde ich gefragt "Würdest du nicht gerne wissen, was passiert wäre wenn...",
    wieder und wieder höre ich Leute sagen "Ich wünschte gerne, wo ich jetzt stehen würde hätte ich...",
    wieder und wieder lese ich "Damals, ... war alles noch so einfach." oder "Ich wünschte ich könnte nochmal...".

    Sicherlich, die Vorstellungskraft des Menschen drängt uns gerade wegs da hin, zu überlegen und sich vorzustellen: "Was wäre wenn..."

    Aber ist es wirklich zuträglich? Neigt der Mensch nicht dazu, sich nicht mit dem zufrieden zu geben, was er hat?
    Genau das ist der Grund, warum ich solche Gedanken versuche zu vermeiden. Ich lebe nicht in der Vergangenheit sondern im hier und jetzt.
    Das Heute ist mir zu wichtig, alsdass ich die Zeit damit verschwenden möchte, an ein Morgen zu denken welches nicht mehr eintreten kann.
    Ich versuche jede Situation bestmöglich zu erledigen und akzeptiere den Ausgang.

    Wir dürfen nicht in eine Art von Nostalgie verfallen und uns vergangene Zeiten zurück wünschen. Es könnte zu unerwünschten Einsichten
    führen die die Nostalgie könnte in Melancholie umschwenken. Solche Gedanken des Trübsales kosten Zeit. Zeit ist eine Ressource, welche
    bei mir zumindest sehr spärlich gesäht ist. Darum auch das Sinnbild "der Treibsand unserer Zeit".

    Wer weiß? Vielleicht ändert sich das irgendwann. Vielleich sage auch ich irgendwann "Was wäre passiert wenn ich..." doch werde ich nicht
    versuchen es drauf ankommen zu lassen. Ich bin zufrieden mit meinem Leben und das sollten andere auch sein. Und was wenn das Leben doch mal
    eine Talfahrt nimmt und es nicht ganz so wünschenswert läuft? Dann nimmt man es selbst in die Hand.

    Den wie sagte schon Terry Prince?

    "Your life is your garden, your thoughts are the seeds. If your life isn't awesome, you've been watering the weeds."

    How to: Installieren von Redmine auf einem Debian mit NginX und Mongrel-Cluster

    Hier eine kleine Installationsanleitung des Projektmanagementsystemes Redmine auf einem Linux Debian (Squeeze, Sid oder Lenny mit Backports) unter Einbeziehung der Webserver NginX und Mongrel-Cluster

    Anmerkung: folgende Installationsanleitung als root, oder entsprechende Befehle via sudo ausführen!

    Installieren und Testen von Redmine aus Debianquellen

    Als erstes installieren wir uns die nötigen Packete aus der Versionsverwaltung, welche da wären:

  • redmine (1.0.5)
  • redmine-* (1.0.5)
  • rails (2.3.5)
  • rake (0.8.7)
  • ruby (4.5, Abhängigkeit zum Packet ruby1.8, bei mir in Version 1.8.7.302)
  • In Klammern sehen sie die in meiner Installation verwendeten Versionsnummern. redmine-* steht hier für die Packete redmine-mysql, redmine-pgsql und redmine-sqlite. Je nachdem, welche Datenbank sie verwenden wollen, suchen sie sich eines der oben genannten aus.

    ~# aptitude install redmine redmine-sqlite rails rake ruby

    Folgen sie der Installationsanleitung zum automatischen einrichten der Datenbank. Normalerweise sind das nur wenige klicks und funktioniert  automatisch.

    Anschließend testen wir die Instanz:

    ~# cd /usr/share/redmine/
    /usr/share/redmine# ruby script/server -e production

    Es ist möglich, das Sie folgenden Traceback bekommen:

    => Booting WEBrick...
    => Rails 2.3.5 application starting on http://127.0.0.1:3000
    /usr/share/redmine/vendor/rails/railties/lib/rails/rack/log_tailer.rb:10:in `size': No such file or directory - /usr/share/redmine/log/production.log (Errno::ENOENT)
    from /usr/share/redmine/vendor/rails/railties/lib/rails/rack/log_tailer.rb:10:in `initialize'
    from /usr/lib/ruby/1.8/rack/builder.rb:54:in `new'
    from /usr/lib/ruby/1.8/rack/builder.rb:54:in `use'
    from /usr/lib/ruby/1.8/rack/builder.rb:73:in `call'
    from /usr/lib/ruby/1.8/rack/builder.rb:73:in `to_app'
    from /usr/lib/ruby/1.8/rack/builder.rb:71:in `inject'
    from /usr/lib/ruby/1.8/rack/builder.rb:73:in `each'
    from /usr/lib/ruby/1.8/rack/builder.rb:73:in `inject'
    from /usr/lib/ruby/1.8/rack/builder.rb:73:in `to_app'
    from /usr/share/redmine/vendor/rails/railties/lib/commands/server.rb:95
    from /usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
    from /usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `require'
    from script/server:3

    Aus einem mir unerklärlichen Grund, legt das Debianpacket die logfiles nicht an. Das ist leicht von Hand zu realisieren:

    /usr/share/redmine# mkdir log
    /usr/share/redmine# touch log/production.log

    Anschließend testen wir die Instanz erneut:

    /usr/share/redmine# ruby script/server -e production
    => Booting WEBrick...
    => Rails 2.3.5 application starting on http://127.0.0.1:3000
    => Call with -d to detach
    => Ctrl-C to shutdown server

    Nun im Browser auf http://127.0.0.1:3000 zugreifen. Sollten sie Redmine sehen, beenden sie den WEBrick-Server mittels Strg+C

    Installieren und Configurieren von Mongrel-Cluster

    Im nächsten Schritt installieren wir den Webserver Mongrel-Cluster. Dazu brauchen wir folgende Packete:

  • mongrel (1.1.5)
  • mongrel-cluster (1.0.5)
  • In Klammern finden Sie wieder die von mir verwendeten Versionsnummern.

    Damit sind wir auch schon fast durch. Sie müssen nur noch mongrel-cluster und nginx entsprechend Konfigurieren:

    /usr/share/redmine# cd /etc/mongrel-cluster
    /etc/mongrel-cluster# touch sites-available/redmine.yml

    Mit einem Editor ihrer Wahl bearbeiten sie die redmine.yml und fügen folgendes ein

    --- 
    group: www-data
    log_file: log/mongrel.log
    port: "3000"
    cwd: /usr/share/redmine/
    environment: production
    user: www-data
    pid_file: tmp/pids/mongrel.pid
    servers: 1

    und verlinken anschließend die Config:

    /etc/mongrel-cluster# cd sites-enabled/
    /etc/mongrel-cluster/sites-enabled# ln -s ../sites-available/redmine.yml .

    Da wir die Group und den User auf "www-data" gesetzt haben, müssen wir noch ein chown durchführen:

    /etc/mongrel-cluster# cd /usr/share
    /usr/share# chown -R www-data:www-data redmine/

    Nun kann die Instanz gestartet werden:

    /usr/share# mongrel_cluster_ctl start

    Installieren und Configurieren von NginX

    Wie auch schon in den beiden Schritten zuvor, müssen wir erst die dafür nötigen Packete installieren:

    • nginx (0.8.54, ich verwende das nginx-extra Packet in selber Version)

    In Klammern finden Sie wieder die von mir verwendeten Versionsnummern.

    Nach der Installation können wir testen, ob der NginX läuft, indem im Browser http://localhost aufgerufen wird. Sollten wir die Defaultpage von NginX sehen "Welcome to nginx!", können wir fortfahren. Der Webserver muss nun nur noch auf unsere mongrel_cluster Instanz weiterleiten. Dazu bearbeiten wir die default config von NginX oder fügen eine neue hinzu:

    /usr/share# cd /etc/nginx/
    /etc/nginx# touch sites-available/redmine
    /etc/nginx# cd sites-enabled/
    /etc/nginx/sites-enabled# ln -s ../sites-available/redmine .

    In unsere neue redmine datei fügen wir nun nur noch folgendes ein:

    server {
         listen  80;
         server_name  redmine.example.com; #Hier ihre Wunschdomain, auf welcher gelauscht werden soll eintragen

         access_log  /var/log/nginx/redmine.example.com.access.log;
         error_log   /var/log/nginx/redmine.example.com.error.log;

         location / {
             proxy_pass http://127.0.0.1:3000/;
         }
    }

    Nun müssen wir nur noch den NginX neustarten und dann können wir unsere Redmineinstanz über die bei server_name eingetragene Domain erreichen.

    /etc/nginx/sites-enabled# /etc/init.d/nginx restart

    'invalid form request token' Error in mongrel 1.1.5 fixen

    Leider gibt es in der im aptitude befindlichen mongrel Version einen Bug, der beim Einloggen immer den Error 'invalid form request token' wirft. Allerdings gibt es dafür einen kleinen aber feinen Patch. Mit einem Editor ihrer Wahl bearbeiten sie die cgi.rb (zu finden in /usr/lib/ruby/1.8/mongrel) und fügen die im nachstehenden Diff durch + hervorgehobenen Zeilen ein (ca Zeile 80):

    =  # remaining possible options they can give
    =  @head['Status'] = options['status'] if options['status']@head['Content-Language'] = options['language'] if options['language']
    =  @head['Expires'] = options['expires'] if options['expires']
    =
    +  # Bugfix for "invalid form request token" during login with redmine
    +  @head['cookie'] = options['cookie'] if options['cookie']
    +  options.delete('cookie')
    =
    =  # drop the keys we don't want anymore
    =  REMOVED_KEYS.each {|k| options.delete(k) }
    =
    =  # finally just convert the rest raw (which puts 'cookie' directly)
    =  # 'cookie' is translated later as we write the header out
    =  options.each{|k,v| @head[k] = v}

     

    Noch Fragen? Scheuen Sie sich nicht mir eine Mail zu schreiben.

    CC Musikempfehlung: Astras ~ Maze of Time

    ... interessanter Start in das Lied, gefolgt von einem netten Riff und eingängigen Gitarrensounds...

    Einige Tage voller unruhiger Nächte und wenig Schlaf liegen nun hinter mir und das Wetter erledigt das übrige. Zum krönenden Finale gab es gestern Abend noch eine Party, wo die Musik so garnicht meinen Geschmack getroffen hat. Heute, am Morgen danach, sitze ich auf meinem Bett und brauche Musik um wach zu werden. So sehr ich die Musik von Josh Woodward mag, in diesem Fall wäre sie wohl die Falsche.

    Ich durchforteste meine Musikbibliotek nach Metal, finde aber nur Dinge die mir jetzt ne spur zu kräftig wären: Slayer, Black Messia, Ensiferum... welch Glück das mir just in diesem Moment eine Aufforderung von gestern Abend eingefallen ist: "Ich brauch ne neue Musikempfehlung, Josh Woodward hab ich rauf und runter gehört und kann überall mitsingen." Ein positives Feedback... yay!

    Nachdem ich gut 2 Stunden auf Jamendo herumgeklickt habe, ohne nennenswerten Erfolg (Frust machte sich breit) zeigte der Player auf einmal den Track "Tears from Paradise" von Astras. Ein interessanter Start in das Lied, gefolgt von einem netten Riff und eingängigen Gitarrensounds. Ich beschloss mir das ganze Album anzuhören und finde, ich habe mal wieder einen Glückstreffer gelandet. Gerade die Tracks "Tears from Paradise", "First Blood" und "Guardian of Danger" haben es mir angetan.

    Damit hatte ich meinen Kandidaten für die heutige CC Musikvorstellung und hier sind sie: Eine englisch singende Metalband aus Italien - Astra.

    Wie auch schon das letzte mal findest du in meiner CC Musikbox auf der linken Seite meine aktuelle Empfehlung Astra mit dem Album "Maze of Time". Wenn es gefällt und du willst es besitzen, dann lade es dir doch einfach hier herunter.

    CC Musikempfehlung: Josh Woodward ~ Ashes

    Heute gibt es meine erste Musikempfehlung. Das Album Ashes von Josh Woodward

    Josh Woodward ist mir vor einiger Zeit schon aufgefallen, als ich für ein kleines Adventskalender-Projekt (alle Songs gibt es hier) einige Lieder gesucht habe, welche unter einer CC Lizens stehen. Leider war es aufgrund technischer Probleme damals nicht möglich seine Songs herunter zu laden.

    Mitlerweile geht es und ich bin von seinem Album "Ashes" einfach nur begeistert.
    Eine Stimme, die aus jedem Song eine Balade machen kann und eine Akustikgitarre die jedes erloschene Lagerfeuer wieder entfachen kann. Die perfekte Musik um sich nach einem harten Tag zu entspannen!

    Neugierig geworden? Auf der linken Seite findest du eine Box, in welcher du immer meine aktuellste CC Empfehlung anhören kannst. Herunter laden kannst du dir das Album kostenlos hier.

    Website Relaunch

    Lange hat es gedauert:

    Auf der DZUG Tagung letztes Jahr habe ich mich entschlossen, meine Seite von einem Plone 3.3.5 auf ein Plone 4 zu migrieren. Allerdings hab es mit dem verwendeten Theme einige Probleme und die Umbauarbeiten hätten genau so lange gedauert, wie das Aufsetzen eines eigenen Themes.Doch wie es eben immer ist: Hier fehlt die Zeit, da fehlt die Lust und dann fehlen noch die Ideen. Jetzt habe ich mal die Muse gehabt, mich ran gesetzt und das hier ist dabei heraus gekommen.

    Ich habe mich für eine sehr schlichte Variante entschieden und bin damit zufieden. Demnächst werden noch einige kleine Änderungen folgen und ich habe wieder vor, öfter zu Bloggen.

    Wie gefällt euch die neue Seite? Schreibt's mir doch auf Twitter ;-)

    Folge mir auf Twitter!
    @strunz5644667 kk nochmal an die AOL ... 21.05.2012 15:39
    @strunz5644667 deine Uniadresse? 21.05.2012 15:36
    @lupinodotorg @Raidrion nachher Mumble wegen den Designvorschlägen auf sn.le.misc? 21.05.2012 15:31
    @strunz5644667 hab dir mal ne Mail weitergeleitet... ;-) 21.05.2012 15:22
    @d1etpunk ich wär' ja für MEHR Mumble rumhängen. So fern die #Flaschenpost nich gerade ne Telko hat is dasn Glücksgriff. /cc @HerrLlama 21.05.2012 15:15