OwnCloud und gelöschte Termine

Die Umgebung

Ich betreibe einen lokalen OwnCloud-Server, der primär für gemeinsame Kalender (4 Stück) genutzt wird. Die Clients sind drei iPhones, ein iPad, drei Thunderbirds mit Lightning.

Das Problem

Meine Frau verwaltet Ihre Termine in der Praxis über ihr iPad und synct mal über ein VPN, mal über WLAN. Manchmal auch ein paar Tage lang nicht.

Jedenfalls ist es bislang in den letzten sechs Monaten zwei Mal vorgekommen, daß Termine von ihr verschwunden sind. Darf nicht passieren, Sie hat Kundenkontakte.

Nun ja, erst mal in die Datenbank von OwnCloud geschaut. Ach ne, das darf ja wohl nicht wahr sein. Da werden doch tatsächlich Einträge aus der Termin-Tabelle wirklich gelöscht.

Klar, Speicherplatz ist so kostbar, da muß man schon auf jedes Byte schauen.

Also an sich keine Möglichkeit, rauszukriegen, wann der Termin verschwunden ist.

Hab dann mal über meine (täglichen) Backups manuell eruiert, wann der Termin verschwunden ist, hilft aber natürlich nicht wirklich weiter.

Was ich haben will

Löschvorgänge dürfen keine Einträge löschen, sondern sollen nur ein delete-flag setzen. Am Besten mit einem Löschen nur mit Nachfrage, wenn das System selber was löschen will. Hat unser Palm Organizer selig schon gekonnt, sollte also nicht so schwer sein.

Aber ich bau natürlich nicht die OwnCloud um, so viel Zeit habe ich nicht.

Die Lösung

Bei Löschvorgängen, egal ob vom Benutzer oder vom System angestoßen, werden die Einträge in eine „Backup“-Tabelle kopiert und als Termin einem neuen Kalender „gelöscht“ zugewiesen.

Wenn jetzt ein Termin gelöscht wird, kann ich nachschauen, wann das passierte und was für ein Termin das war.

Außerdem erscheint der gelöschte Termin als neuer Termin im gelöscht-Kalender (auf rot gestellt), so kann ich verifizieren, ob der wirklich gelöscht werden soll.

Die Backup-Tabelle

Ich habe die Tabelle oc_clndr_objects mit phpMyAdmin ohne Inhalt als Tabelle oc_clndr_delete_objects kopiert und um die Felder id (Autoincrement), timestamp und converted (bool) ergänzt. Die id der Originaltabelle habe ich in objectid umbenannt.
oc_clndr_delete_objects

Der Trigger

Damit diese Tabelle beim Löschen mit den Einträgen befüllt wird, brauche ich einen Trigger auf der Tabelle oc_clndr_objects. Der muß als BEFORE DELETE angelegt werden und sieht so aus:

BEGIN
/* Gewünschten Kalender abfragen */
if old.calendarid = 7 THEN
/* Eintrag in die delete-Tabelle schreiben */
INSERT INTO oc_clndr_delete_objects (objectid,calendarid,objecttype,startdate,enddate,repeating,summary,calendardata,uri,lastmodified) VALUES (old.id,old.calendarid,old.objecttype,old.startdate,old.enddate,old.repeating,old.summary,old.calendardata,old.uri,old.lastmodified);
END IF;
END

Der CRON-Job

Bei mysql ist es leider nicht möglich, in einem Trigger die auslösende Tabelle zu bearbeiten, deshalb kann der neue Eintrag nur über einen CRON-Job erzeugt werden.

Ich mache das mit der folgenden PHP-Datei, die vom CRON-Dienst alle 15 Minuten aufgerufen wird:

<?php
$link=mysql_connect(„localhost“,“xxx“,“xxx“);
$db = „owncloud“;
mysql_select_db($db, $link);
// Kalendereinträge
$sql=“Insert into oc_clndr_objects (id,calendarid,objecttype,startdate,enddate,repeating,summary,calendardata,uri,lastmodified) „;
$sql=$sql.“SELECT objectid,13,objecttype,startdate,enddate,repeating,summary,calendardata,uri,lastmodified FROM oc_clndr_delete_objects „;
$sql=$sql.“WHERE calendarid=7 AND converted<>1″;
$res=mysql_query($sql);
$sql=“Update oc_clndr_delete_objects SET converted=1 WHERE calendarid=7 AND converted<>1“;
$res=mysql_query($sql);
?>

Ein paar Hinweise zum Schluss

Das System hat mittlerweile einige Updates und den Umzug auf einen anderen Server mitgemacht.

Die Updates laufen ohne Probleme durch, Trigger und Cron funktionieren weiterhin.

Beim Umziehen der OwnCloud auf einen anderen Server:

  • Beim Umzug der Datenbank wird der Trigger ebenfalls übertragen – fein
  • Die php-Datei ebenfalls umziehen
  • Den Cron-Job neu einrichten und testen, ich muß bald auf mysqli umstellen, php spuckt Warnungen aus:

    PHP Deprecated:  mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /var/www/owncloud/prevent_delete.php on line 7

    Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /var/www/owncloud/prevent_delete.php on line 7

 

Veröffentlicht unter IT-Technik | Kommentare deaktiviert für OwnCloud und gelöschte Termine

PhoneGap 3 Entwicklungsumgebung unter Windows und OS X

Um CrossPlatform-Apps zu erstellen, ist momentan eine PhoneGap-Einrichtung sinnvoll.

Und da die Installation nicht ganz ohne Aufwand ist, schreibe ich hier mal ein Protokoll.

Windows

Alle Programme sollten in der zum System passenden Version (32bit/64bit) installiert werden.

Alle Installationen sollten mit Admin-Rechten durchgeführt werden.

Ich werde diese Ordnerstruktur verwenden:

E:\AndroidD:\Android\android-sdk
E:\Android\apache-ant
E:\Android\Apps

Der App-Ordner kann aber auch auf einem Netzlaufwerk liegen, das dann auch ein Webserver-Laufwerk sein kann. So kommt man auch mit einem Browser an die App.

Java JDK installieren

Download: http://www.oracle.com/technetwork/java/javase/downloads/index.html

Einfach immer mit Ja, OK und Weiter alles abnicken.

Folgende Systemvariablen setzen:

  • JAVA_HOME: C:\Program Files\Java\jdk1.x.x_xx
  • Path: %JAVA_HOME%\bin
    Die Pfadangabe am Ende mit vorangestelltem ; anhängen

Android SDK-Tools installieren

Hinweis:
Es ist nicht die komplette Umgebung mit Eclipse etc. nötig, die SDK-Tools reichen.

Download: http://developer.android.com/sdk/index.html

Installation in beliebigen Ordner, bei mir E:\Android\android-sdk

Folgende Systemvariablen setzen:

  • Path: E:\Android\android-sdk\platform-tools;E:\Android\android-sdk\tools
    Die Pfadangabe am Ende mit vorangestelltem ; anhängen

SDK-Manager starten und folgende Einstellungen vornehmen:

  • Android SDK Build-tools V21 abwählen
  • Android SDK Build-tools V19.1 auswählen
  • Android 5 komplett abwählen
  • Android 4.4.2 komplett auswählen

Auf „Install xx packages“ klicken und Lizenzen bestätigen

Apache-Ant installieren

Download: http://ant.apache.org/bindownload.cgi

In geeigneten Ordner auspacken, bei mir E:\Android\apache-ant

Folgende Systemvariablen setzen:

  • ANT_HOME: E:\Android\apache-ant
  • Path: %ANT_HOME%\bin
    Die Pfadangabe am Ende mit vorangestelltem ; anhängen

GitHub installieren

Download: https://windows.github.com/

Auf der Kommandozeile folgendes eingeben:

E:\Android> git config –global user.name „YOUR NAME“

E:\Android> git config –global user.email „YOUR EMAIL ADDRESS“

Anwendung dann noch einmal starten und wieder beenden.

Node.js installieren

Download: http://nodejs.org/

Installieren und alles mit OK und Weiter durchklicken.

PhoneGap installieren

Auf der Kommandozeile folgendes eingeben:

E:\Android> npm install -g phonegap

Win-AVD-ManagerAndroid-Device erstellen

Auf der Kommandozeile den AVD-Manager starten:

E:\Android> android avd

Auf dem Register „Device Definitions“ ein passendes Gerät aussuchen. Ich nehme ein „Nexus One“ und klicke auf „Create AVD“. Win-AVD-Manager-DeviceDann noch diese Einstellungen vornehmen:

  • Target: Android 4.4.2 API19
  • CPU: ARM
  • Skin: no skin

Alles bestätigen und schließen.

Tests durchführen

Die Tests laufen alle in einem „DOS-Fenster“, heute heißt das ja eher Shell oder Kommandozeileninterpreter 🙂

Create-Test

In den Ordner für die Apps wechseln.

E:\Android\Apps> phonegap create HelloWorld

Win-CreateHelloWorld

Jetzt sollte es hier einen Ordner HelloWorld geben.

E:\Android\Apps> cd HelloWorld

E:\Android\Apps\HelloWorld>

Plugin-Test

Auch wenn diese App kein Plugin braucht, zum Testen ob es funktioniert, im Ordner der App folgendes eingeben:

E:\Android\Apps\HelloWorld> phonegap local plugin add org.apache.cordova.device

Win-Plugin

Hinweis:
Bei praktisch allen Beschreibungen habe ich eine andere Syntax gefunden, die kann aber in meinem Netz nicht aufgelöst werden:
phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-device.git
Auch Variationen der URL durch die IP, mit http oder ohne Protokollangabe haben bei mir nicht funktioniert. Keine Ahnung woran es liegt, ich habe diverse DNS-Server ausprobiert.

Build-Test

E:\Android\Apps\HelloWorld> phonegap build android

Win-build

Win-EmulatorEmulator-Test

E:\Android\Apps\HelloWorld> phonegap run android –emulator

Jetzt dauert es eine ganze Weile,bis der Emulator startet und das abgebildete Default-Bild zeigt.

Android-Test

Dazu muss natürlich ein Android-Gerät im USB-Debug-Modus angeschlossen sein.

E:\Android\Apps\HelloWorld> phonegap run android –device

Hinweis:
Falls die App schon auf dem Gerät ist, vor einer Neuinstallation diese löschen, sonst gibt es Fehlermeldungen.

OS X

not yet ready – sorry, no time

Quellen

Veröffentlicht unter IT-Technik | Kommentare deaktiviert für PhoneGap 3 Entwicklungsumgebung unter Windows und OS X

Buchvorstellung: Webtechnologien – All in One

Hallo da draußen,

buchcoverheute teile ich mal technische Informationen auf einem anderen Wege mit 🙂

Und zwar habe ich mein Buch „Webtechnologien – All in One“ fertiggestellt und wollte es euch nicht vorenthalten.

Damit habe ich eine meiner Veranstaltungen gewissermaßen in Buchform gebracht. Also nicht ein schnödes Lernen von Syntax, Befehlen, mit mehr oder weniger nützlichen Beispielen, sondern ein echter praktischer Einstieg in alle wichtigen Techniken, wenig Theorie, viel Praxis.

Auszug aus dem Vorwort

Der Gedanke zu diesem Buch kam mir, als ich für eines meiner IT-Trainings keine passende Lektüre gefunden habe. Die einzigen Bücher, die alle notwendigen Themen abdeckten, waren zum einen ohne Neuauflage seit vielen Jahren auf dem Markt und deshalb vergriffen und zum anderen so umfangreich, dass sie sich zwar gut als Nachschlagewerk, nicht jedoch als begleitende Lektüre zu einer Veranstaltung eigneten.

Also beschloss ich, ein Buch zu schreiben, mit dem Sie sich in recht kurzer Zeit ein umfangreiches Wissen über moderne Webtechnologien selber aneignen können.

Dieses Buch erhebt nicht den Anspruch, Sie mit allen Technologien bis in die Tiefe vertraut zu machen. Mein Ziel ist es vielmehr, mit Ihnen anhand eines kleinen Web-Projektes die meisten der heute üblichen Techniken zu erarbeiten.

Wenn Sie dieses Buch durchgearbeitet haben, werden Sie in der Lage sein, selber zu entscheiden, welche der Techniken Sie durch weiterführende Literatur oder Veranstaltungen vertiefen möchten, welche Vor- und Nachteile die jeweiligen Technologien haben und mit welchem Aufwand Sie bei der Entwicklung eigener Projekte rechnen müssen.

Mir ist natürlich klar, dass die Entwicklung von Webseiten durch den Einsatz passender Entwicklungsumgebungen massiv erleichtert werden kann. Dennoch verzichte ich in diesem Buch darauf, denn so praktisch diese Entwicklungsumgebungen auch sein mögen, am Anfang müssen Sie sich erst einmal viel Wissen aneignen, um mit ihnen umgehen zu können. Und das lenkt von den eigentlichen Themen dieses Buches ab. Deshalb empfehle ich Ihnen, nur einen einfachen Editor zu verwenden.

Dieses Buch gliedert sich in drei wesentliche Teile. Im ersten Teil, dem Fundament, werden Sie die die Technologien HTML, PHP und CSS kennenlernen und eine erste strukturelle Umsetzung des Projektes erstellen. Im zweiten Teil, dem Rohbau, werden Sie die Funktionalität der einzelnen Seiten erstellen und dazu Formulare sowie die Datenbanksprache SQL kennenlernen. Und im dritten Teil, der Fertigstellung, werden Sie Javascript und das Javascript-Framework jQuery kennlernen, um den Benutzerkomfort der Seiten zu steigern zusätzliche Funktionalitäten zu ermöglichen.

Veröffentlicht unter IT-Technik | Verschlagwortet mit , , , , , , | Kommentare deaktiviert für Buchvorstellung: Webtechnologien – All in One

ESXi 5.5 auf Mac Pro 4.1

Ziel: OS X als VM laufen lassen

Vorhanden: Mac Pro 4.1 mit 2 x Xeon 4 Kerner und 24GB RAM.

Installation von ESXi 5.5 auf Mac Pro 4.1

CD einlegen
So ein Mist, wie geht denn dieses Laufwerk ohne Apple-Tastatur auf?
USB-CD-Laufwerk angestöpselt 🙂

8GB-USB-Stick eingesteckt

Booten, die Installation wie gehabt vornehmen, läuft astrein durch.

Dann noch wie benötigt IP-Adresse etc. anpassen, SSH aktivieren etc.

Den vSphere-Client von Windows aus öffnen, so ein Mist, unter XP läuft der nicht mehr.
(Ich habe ihn jetzt in einer VM mit Windows 7 laufen)

VM einrichten für das gewünschte OS X, und per durchgereichtem USB-Stick oder ISO installieren.

Hat bei mir für Lion, Mountain Lion und Mavericks funktioniert.

Probleme

Zwei Netze mit PPTP

Ich brauche ein vollständig eigenständiges Netzwerk auf dem Mac Pro.

Neuen Switch 2 erstellen, von der Netzwerkkarte (ich nutze nur die eth0) abkoppeln und die gewünschten VM an diesen Switch 2 koppeln.

Neue VM mit zwei Netzwerkkarten anlegen, IPCOP installieren mit rot und grün. Die grüne Karte dem neuen Switch 2 zuweisen, die rote Karte dem dem anderen Switch 1 (der mit Anschluß an eth0 vom Mac Pro)

Funktioniert soweit alles bestens, bis auf:

Weder mit dem IPCop noch dem Linuxrechner als PPTP-Server konnte von „außen“, also über den Switch 1, eine PPTP-Verbindung aufgebaut werden.

Hat einige Stunden gedauert, bis ich den Fehler bei der E1000-Netzwerkkartenvirtualisierung vermutet habe. Die E1000 hat nämlich einen bug und kann kein GRE verarbeiten.

Umstellen auf VMXNET 3 löst das Problem.

OS X als VM

Installation: Bilderbuch, läuft problemlos durch.

Die Installation der VMWareToolsist ebenfalls kein Problem und funktioniert sogar 🙂

Ich bin frustriert: Die Bildschirmfreigabe von einen VM-Mac VNC ist lahm, sehr lahm. Ich verbinde von Windows aus mit UltraVNC und RealVNC, ersteres ist etwas besser, aber alle Sonderzeichen sind murks.

Vom MacBook aus ist die Wiedergabe schön auf den Bildschirm skaliert und halbwegs flüssig.

Aber überhaupt kein Vergleich zum RDP bei Windows. Hat Apple sowas eigentlich nicht nötig? Wie wollen die denn je in die Businesswelt reinkommen, wenn nicht mal eine effiziente Fernbedienung geht??? Oder arbeiten die nicht remote?

Linux als vM

Ich installiere ein Deebian 7 als Netinst und spiele da folgendes drauf:

apache 2, Postfix, Roundcube, fetchmail, php5, mysql, phpmyadmin, Webmin, samba, pptpd

Läuft alles wie am Schnürchen, Debian halt 🙂

Windows als VM

Dann kommt noch eine VM mit Windows 7 dazu, da kommen die vSphere Tools drauf, also der Client und der Converter.

Tools installieren und 100 Millionen Windows-Updates herunterladen.

Remote Desktop aktivieren

Später wird dieser Rechner auch noch die USV verwalten und das System bei Bedarf gezielt herunterfahren.

Veröffentlicht unter IT-Technik | Verschlagwortet mit , , , , , | Kommentare deaktiviert für ESXi 5.5 auf Mac Pro 4.1

VMWare ESXi 5.0 auf MacBook 4.1

Ziel: virtuelle OSX-Systeme

Vorhanden: MacBook 4.1 mit 4GB RAM und 100GB HD

Problem: Der Netzwerkchip des MacBooks: Marvell Yukon 88E8055 VEN_11AB&DEV_436A

Lösung: Sky2-Treiber einbinden

  1. Auf einer VMWare Workstation eine Installation auf die physikalische Platte des MacBook machen (Platte dazu mit USB-Adapter am PC anschließen)
  2. In der Verwaltungsoberfläche bei Troubleshooting SSH und Konsole aktivieren
  3. Sky2-VOB-Datei per sftp nach /bootbank/ kopieren
  4. Per SSH einloggen und folgende Befehle eingeben:
    1. esxcli software acceptance set --level=CommunitySupported
    2. esxcli software vib install -v /bootbank/net-sky2-1-1.1.0.x86_64.vib
  5. Virtuellen Rechner herunterfahren
  6. Platte wieder in den Mac einsetzen
  7. Beim Starten die Wahltaste (Alt) gedrückt halten
  8. System fährt jetzt hoch

Problem: Netzwerk leider noch nicht vorhanden

Lösung: Sky2-Treiber aktivieren

  1. Mit FN-Alt-F1 auf die Konsole wechseln und anmelden
  2. lspci -p zeigt die PCI-Geräte
  3. vmkload_mod sky2 bindet die Karte ein
  4. Mit FN-Alt-F2 in die Verwaltung gehen und bei den Netzwerkeinstellungen die Karte aktivieren

Et voila, das MacBook ist ein ESXi-Server 🙂

Problem 1: Dummerweise vergisst der Mac die Einbindung bei einem Neustart 🙁

Problem 2: Die Platte läßt sich nicht als Datenspeicher nutzen, auch hier fehlt ein Treiber.

Ich hab jetzt meinen Mac Pro, auf dem läuft ESXi 5.5 ganz wunderbar.

Quellen

http://www.wyattspace.com/2012/08/17/esxi5-marvell-sky2/

http://trentent.blogspot.de/2012/09/esxi-5-on-older-macbook-41.html

http://trentent.blogspot.de/2012/09/esxi-51-on-macbook-41.html

Sky2-Treiber

Veröffentlicht unter IT-Technik | Verschlagwortet mit , , , , | Kommentare deaktiviert für VMWare ESXi 5.0 auf MacBook 4.1

Contao Extension Erstellung – So funktioniert’s

Einleitung

Da ich ein Ferienhaus verwalten soll, habe ich mich mal nach passenden Extensions umgesehen.

Für die 3.1er Version von Contao finde ich da

  • zibepla
  • und diverse andere, die allerdings kommerziell sind

Also habe ich mir zibepla mal angesehen, aber so richtig passen wollte es nicht. Vor allem kann man eine Belegung keinem Kunden zuordnen.

Also habe ich mir gedacht, jetzt baue ich mal selber eine Extension 🙂

Die Planung

Backend

Im Backend möchte ich Termine für ein Ferienhaus reservieren können, mit dem Namen des Mieters, Anreise- und Abreisedatum und einem Textfeld für Anmerkungen.

Außerdem möchte ich Terminüberschneidungen optisch angezeigt bekommen.

Frontend

Im Frontend soll der Besucher den Belegungsplan möglichst übersichtlich zu sehen bekommen.

Tabelle

Da ich nur ein Haus verwalten möchte, und diese Extension erst mal auch noch einfach bleiben soll, komme ich mit einer Tabelle tl_bepla aus.

An Feldern benötige ich kunde, hinweis, von und bis (und natürlich die von Contao benötigten Felder id und timestamp).

Die Vorbereitung

Ich lege unter /system/modules einen neuen Ordner bepla an. Dieser erhält diese Ordnerstruktur:

bepla/assetsordnerstruktur
bepla/config
bepla/dca
bepla/languages
bepla/languages/de
bepla/modules
bepla/templates

Die Datei config.php

Im config-Ordner lege ich die Datei config.php mit diesem Inhalt (gekürzt) an:

<?php if (!defined('TL_ROOT')) die('You can not access this file directly!');
// BACK END MODULES
// Eintrag im Backend unter "Inhalte" (content) anlegen
$GLOBALS['BE_MOD']['content']['bepla'] = array(
	'tables' => array('tl_bepla'),                      // Verwendete Tabelle
	'icon'   => 'system/modules/bepla/assets/icon.gif'  // Verwendetes Icon
	);
// FRONT END MODULES
$GLOBALS['FE_MOD']['Belegungsplan'] = array
(
	'bepla_table'     => 'ModuleBeplaTable',
);
?>

Damit das Icon auch angezeigt wird, kopiere ich die Icon-Datei in den Ordner assets.

Die Datei tl_bepla.php

Teil 1: DCA-Definitionen

Diese Datei ist die DCA-Datei, die beschreibt, was es im Backend für Möglichkeiten gibt. Außerdem definiert diese Datei auch die benötigte Tabelle tl_bepla.

Wichtig: Tabelle und DCA-Datei müssen den gleichen Namen haben.

<?php if (!defined('TL_ROOT')) die('You can not access this file directly!');
/**
 * Table tl_bepla
 */
$GLOBALS['TL_DCA']['tl_bepla'] = array
(
	// Config
	'config' => array
	(
		'dataContainer'         => 'Table',
		'enableVersioning'      => true,
		'sql' => array
		(
			'keys' => array
			(
				'id' => 'primary'
			)
		)
	),
	// List
	'list' => array
	(
		'sorting' => array
		(
			'mode'              => 1,
			'fields'            => array('von'),
			'flag'              => 7,
			'panelLayout' 		=> 'filter,search,limit'
		),
		'label' => array
		(
			'fields'            => array('kunde'),
			'format'            => '%s',
			'label_callback'	=> array('tl_bepla','listBepla')
		),
		'operations' => array
		(
			'edit' => array
			(
				'label'         => &$GLOBALS['TL_LANG']['tl_bepla']['edit'],
				'href'          => 'act=edit',
				'icon'          => 'edit.gif'
			),
			'copy' => array
			(
				'label'         => &$GLOBALS['TL_LANG']['tl_bepla']['copy'],
				'href'          => 'act=copy',
				'icon'          => 'copy.gif'
			),
			'delete' => array
			(
				'label'         => &$GLOBALS['TL_LANG']['tl_bepla']['delete'],
				'href'          => 'act=delete',
				'icon'          => 'delete.gif',
				'attributes'	=> 'onclick="if(!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\'))return false;Backend.getScrollOffset()"'
			),
			'show' => array
			(
				'label'     	=> &$GLOBALS['TL_LANG']['tl_bepla']['show'],
				'href'      	=> 'act=show',
				'icon'      	=> 'show.gif'
			)
		)
	),
	// Edit
	'edit' => array
	(
		'buttons_callback' 	=> array()
	),
	// Palettes
	'palettes' => array
	(
		//'__selector__'    => array(''),
		'default'           => '{title_legend},kunde,von,bis,hinweis'
	),
	// Subpalettes
	'subpalettes' => array
	(
		''                  => ''
	),
	// Fields
	'fields' => array
	(
		'id' => array
		(
			'sql'           => "int(10) unsigned NOT NULL auto_increment"
		),
		'tstamp' => array
		(
			'sql'           => "int(10) unsigned NOT NULL default '0'"
		),
		'kunde' => array
		(
			'label'			=> &$GLOBALS['TL_LANG']['tl_bepla']['kunde'],
			'inputType'		=> 'text',
			'exclude'       => true,
			'search'		=> true,
			'eval'			=> array('mandatory'=>true, 'maxlength'=>64),
			'sql'           => "varchar(64) NOT NULL default ''"
		),
		'hinweis' => array
		(
			'label'			=> &$GLOBALS['TL_LANG']['tl_bepla']['hinweis'],
			'inputType'		=> 'textarea',
			'eval'          => array('rte' => 'tinyFlash'),
			'sql'           => "text NULL"
		),
		'von' => array
		(
			'label'			=> &$GLOBALS['TL_LANG']['tl_bepla']['von'],
			'inputType'     => 'text',
			'default'       => time(),
			'eval'          => array('mandatory'=>true, 'rgxp'=>'date', 'datepicker'=>$this->getDatePickerString(), 'tl_class'=>'w50 wizard'),
			'sql'           => "int(10) unsigned NOT NULL default '0'"
		),
		'bis' => array
		(
			'label'			=> &$GLOBALS['TL_LANG']['tl_bepla']['bis'],
			'inputType'     => 'text',
			'default'       => time(),
			'eval'          => array('mandatory'=>true, 'rgxp'=>'date', 'datepicker'=>$this->getDatePickerString(), 'tl_class'=>'w50 wizard'),
			'sql'           => "int(10) unsigned NOT NULL default '0'"
		)
	)
);
// ***** An diese Stelle kommt die Routine zur Anpassung der Übersichtsliste im Backend
?>

Für ausführliche Erklärungen zum Aufbau einer DCA-Datei verweise ich auf die offizielle Doku.

Hier nun ein paar zusätzliche Erklärungen:

Im List-Bereich unter ‚label‘ rufe ich eine eigene Routine auf, mit der ich die Ausgabe der Belegungsliste im Backend nach meinen Wünschen anpasse. So werden mir etwa Terminüberschneidungen gezeigt.

Der Bereich ‚fields‘ definiert die Tabelle tl_bepla, das ging früher (vor Version 3) über eine Datei database.sql im config-Ordner.

Teil 2: Anpassung der Listenausgabe

backend_listeDa die default-Listenausgabe nur sehr eingeschränkte Daten ausgibt, wollte ich die auf jeden Fall ändern. Ich möchte nämlich den Belegungszeitraum, den Namen des Mieters, die Hinweise und vor allem Meldungen über Terminprobleme direkt sehen können.

Also habe ich den list-Eintrag ‚label‘ um eine Callback-Funktion erweitert.

Folgender Code gehört ganz an’s Ende der DCA-Datei tl_bepla.php:

class tl_bepla extends Backend {
  public function listBepla($row, $label)
	{
	// $row enthält alle Felder der Datenbanktabelle
	// $label enthält die Daten aus $GLOBALS['TL_DCA']['tl_bepla']['list']['label'] und wird hier nicht benötigt
	$erg="<div>";
	$erg=$erg."<div><strong>".date('d.m.Y',$row['von'])." - ".date('d.m.Y',$row['bis'])." ".$row['kunde']."</strong></div>";
	$erg=$erg."<div>".$row['hinweis']."</div>";
	$erg=$erg."</div>";
	// Plausibilitätsprüfung
	$style="style=\"font-weight:bold; color:#f00;\"";
	$error[0]="";
	$error[1]="";
	// v und sind die aktuellen Werte, von und bis die Datenbankspalten
	// 1. v > b
	if ($row['von'] > $row['bis']) $error[0]="<div $style>Anreisetag liegt nach Abreisetag</div>";
	// 2. v > von und v < bis : Starttermin liegt in belegtem Bereich
	$objData = $this->Database->execute("SELECT id from tl_bepla where ".$row['von']." > von and ".$row['von']." < bis");
	$c= $objData->numRows; // Anzahl der Ergebnisse
	if ($c>0) $error[1]="<div $style>Buchungsüberschneidung</div>";
	// 3. b > von und b < bis : Endetermin liegt in belegtem Bereich
	$objData = $this->Database->execute("SELECT id from tl_bepla where ".$row['bis']." > von and ".$row['bis']." < bis");
	$c= $objData->numRows; // Anzahl der Ergebnisse
	if ($c>0) $error[1]="<div $style>Buchungsüberschneidung</div>";
	// 4. v < von und b > bis : Komplette Überschneidung
	$objData = $this->Database->execute("SELECT id from tl_bepla where ".$row['von']." < von and ".$row['bis']." > bis");
	$c= $objData->numRows; // Anzahl der Ergebnisse
	if ($c>0) $error[1]="<div $style>Buchungsüberschneidung</div>";
	$erg=$error[0].$error[1].$erg;
	return $erg;
  }	
}

Die Language-Dateien

Unter languages/de erstelle ich zwei Dateien, mit denen ich die korrekte Beschriftung steuere.

Die Datei modules.php

<?php if (!defined('TL_ROOT')) die('You can not access this file directly!');
// Back end modules
// Deutsche Beschriftung für den BackEnd-Eintrag unter Inhalte
$GLOBALS['TL_LANG']['MOD']['bepla'] = array('Belegungsplan', 'Verwalten Sie die Belegung hier');
// Front end modules
$GLOBALS['TL_LANG']['FMD']['bepla_table'] = array('Belegungsplan-Tabelle', 'Zeigt die aktuelle Belegung an');
?>

Die Datei tl_bepla.php

<?php if (!defined('TL_ROOT')) die('You can not access this file directly!');
// Fields
$GLOBALS['TL_LANG']['tl_bepla']['von']			= array('Anreisetag', 'Geben Sie den Anreisetag hier ein.');
$GLOBALS['TL_LANG']['tl_bepla']['bis']       	= array('Abreisetag', 'Geben Sie den Abreisetag hier ein.');
$GLOBALS['TL_LANG']['tl_bepla']['kunde']      	= array('Kundenname', 'Geben Sie den Namen des Kunden hier ein.');
$GLOBALS['TL_LANG']['tl_bepla']['hinweis']    	= array('Hinweise', 'Geben Sie zusätzliche Hinweise zum Kunden hier ein.');

// Legends
$GLOBALS['TL_LANG']['tl_bepla']['title_legend'] = 'Buchungsdaten';

// Buttons
$GLOBALS['TL_LANG']['tl_bepla']['new']    = array('Neue Buchung', 'Neue Buchung anlegen');
$GLOBALS['TL_LANG']['tl_bepla']['show']   = array('Buchungsdetails', 'Details der Buchung ID %s anzeigen');
$GLOBALS['TL_LANG']['tl_bepla']['edit']   = array('Buchung bearbeiten', 'Buchung ID %s bearbeiten');
$GLOBALS['TL_LANG']['tl_bepla']['copy']   = array('Buchung kopieren', 'Buchung ID %s kopieren');
$GLOBALS['TL_LANG']['tl_bepla']['delete'] = array('Buchung löschen', 'Buchung ID %s löschen');
?>

Das Frontend-Modul

Teil 1: Das Modul

Der Name des Moduls, das unter bepla/modules gespeichert ist, muß mit dem in der config-Datei definierten Namen für das Frontend-Modul übereinstimmen, in meinem Fall also ModuleBeplaTable.

In diesem Modul wird eigentlich nichts weiter gemacht, als die Daten aus der Tabelle tl_bepla zu lesen und sie an das FE-Template weiterzugeben.

<?php 
namespace bepla;
if (!defined('TL_ROOT')) die('You can not access this file directly!');
class ModuleBeplaTable extends \Module
{
	protected $strTemplate = 'mod_bepla_table';
	// Generate the module
	protected function compile()
	{
	$arrBelegung = array();
	$objBelegung = $this->Database->execute("SELECT * FROM tl_bepla order by von ");
	while ($objBelegung->next())
		{
		$arrBelegung[] = array
			(
			'von' => $objBelegung->von,
			'bis' => $objBelegung->bis,
			'kunde' => $objBelegung->kunde
			);
		}
	$this->Template->belegung = $arrBelegung;
	}
}
?>

Teil 2: Das Templat mod_bepla_table.html5

Das Template sorgt für die Erstellung der Tabelle im Frontend und muß den Namen haben, der im obigen Modul benutzt wurde, in meinem Fall also mod_bepla_table.php.

<div class="<?php echo $this->class; ?> block"<?php echo $this->cssID; ?><?php if ($this->style): ?> style="<?php echo $this->style; ?>"<?php endif; ?>>
<?php
$monate = array(1=>"Jan",
                2=>"Feb",
                3=>"Mär",
                4=>"Apr",
                5=>"Mai",
                6=>"Jun",
                7=>"Jul",
                8=>"Aug",
                9=>"Sep",
                10=>"Okt",
                11=>"Nov",
                12=>"Dez");
$wochentage = array(1=>"Montag",
					2=>"Dienstag",
					3=>"Mittwoch",
					4=>"Donnerstag",
					5=>"Freitag",
					6=>"Samstag",
					7=>"Sonntag");
$wtk = array( 	1=>"Mo",
				2=>"Di",
				3=>"Mi",
				4=>"Do",
				5=>"Fr",
				6=>"Sa",
				7=>"So");
$GLOBALS['TL_CSS']['bepla'] = 'system/modules/bepla/assets/styles.css';
?>
<?php if ($this->headline): ?>
	<<?php echo $this->hl; ?>><?php echo $this->headline; ?></<?php echo $this->hl; ?>>
<?php endif; ?>

<?php
// letzte Buchung ermitteln
$last=0;
foreach ($this->belegung as $data) if ($data['bis']>$last) $last=$data['bis'];
$monat_ende=date("n",$last);
if ($last==0) $monat_ende=$monat=date("n");
$jahr_ende=date("Y",$last);
$monat_ende=$monat_ende+3;
if ($monat_ende>12)
	{
	$monat_ende=$monat_ende-12;
	$jahr_ende=$jahr_ende+1;
	}
?>

<table border="0" cellpadding="0" class="table_bepla">
<tr>
<td class="monat"></td>
<?php
for ($t=1;$t<=31;$t++) echo "<td class=\"tag\">$t</td>";
?>
</tr>
<?php
$jahr=date("Y");
$monat=date("n");
while ($jahr<$jahr_ende || $monat<=$monat_ende)
	{
	echo "<tr>";
	echo "<td class=\"monat\">".$monate[$monat]." ".$jahr."</td>";
	for ($tag=1;$tag<=31;$tag++) 
		{
		$class="nodate";
		$title="Diesen Tag gibt es nicht";
		$wota="";
		if (checkdate($monat,$tag,$jahr)) 
			{
			$class="frei";
			$curdate=strtotime($jahr."-".$monat."-".$tag);
			$wt=$wochentage[date("N",$curdate)];
			$title="$wt, $tag.$monat.$jahr";
			$wota=$wtk[date("N",$curdate)];
			foreach ($this->belegung as $data)
				{
				$von=$data['von'];
				$bis=$data['bis'];
				if ($von==$curdate && $class=="abreise") 
					{
					$class="wechsel";
					}
				elseif ($von==$curdate && $bis==$curdate) 
					{
					$class="wechsel";
					}
				elseif ($von==$curdate) 
					{
					$class="anreise";
					}
				elseif ($bis==$curdate) 
					{
					$class="abreise";
					}
				elseif ($von<$curdate && $bis>$curdate) 
					{
					$class="belegt";
					}
				}
			}
		echo "<td class=\"$class tag small\" title=\"$title\">$wota</td>";
		}
	echo "</tr>";
	$monat++;
	if ($monat>12) 
		{
		$monat=1;
		$jahr++;
		}
	}
?>
</table>
<table border="0" cellpadding="0" class="table_legende">
	<tr>
		<td class="tag frei"></td><td class="legende">Frei</td>
		<td class="tag anreise"></td><td class="legende">Anreise</td>
		<td class="tag belegt"></td><td class="legende">Belegt</td>
		<td class="tag abreise"></td><td class="legende">Abreise</td>
		<td class="tag wechsel"></td><td class="legende">Wechsel</td>
	</tr>
</table>
</div>

Das einzige interessante hier ist die Einbindung der CSS-Datei, diese liegt, genau wie die benötigten Bilder für die Tabelle, im assets-Ordner.

Die Extension in Contao registrieren

Um die Extension in Contao zum Laufen zu bringen, rufe ich jetzt einmal den Autoload-Creator auf und erzeuge die Dateien für mein Modul bepla.

datenbank_aktualisierenDanach rufe ich in der Erweiterungsverwaltung den Befehl Datenbank aktualisieren auf.

Hier sollte jetzt die Abfrage zur Erstellung der Tabelle tl_bepla erscheinen.

Das Ergebnis

Jetzt noch ein paar Bilder, wie das Ganze aussehen kann.

backend_artikel_anzeige

frontend_belegungstabelle

Download

Die komplette Erweiterung kann man hier herunterladen.

Geplante Erweiterungen

Die komplette Extension ist natürlich (wie meistens) Work in progress 🙂

Außerdem gibt es natürlich noch viel Optimierungspotential.

  • Verwaltung für mehrere Häuser erweitern
  • Optimierte Anzeige im Frontend, idealerweise kombiniert mit einer Buchungsanfrage
  • Integration in meinen OwnCloud-Kalender
  • Komplette Mieterverwaltung, am Besten mit Rechnungserstellung
Veröffentlicht unter IT-Technik | Verschlagwortet mit , , , , , | Hinterlasse einen Kommentar

Contao 3.1 und Extension simple_ajax – ein Beispiel

Heute geht es um die Extension simple_ajax, die leider nur dürftig kommentiert ist.

Aber es lassen sich alle Infos im Web finden, dauert halt etwas. 🙂

Deshalb hier jetzt eine Beschreibung, wie sich ein Ajax-Zugriff von einer FE-Seite realisieren läßt.

  • Die Erweiterung simple_ajax muß natürlich über das Repository installiert werden.
    Im Wurzelverzeichnis der Website finden sich dann diese beiden Dateien:
    SimpleAjax.php
    SimpleAjaxFrontend.php
    Dort steht auch eine Minimalanleitung drin 🙂
  • Unter system/modules lege ich jetzt einen neuen Ordner ajaxrequest an.
    Der Name dieses Ordners kann auch beliebig anders lauten
  • Unter system/modules/ajaxrequest lege ich einen neuen Ordner config an.
  • Unter system/modules/ajaxrequest/config erstelle ich die Datei config.php mit diesem Inhalt:
    <?php
    $GLOBALS['TL_HOOKS']['simpleAjax'][] = array('AjaxRequestClass', 'AjaxRequestMethod'); // Klassenname - Methodenname
    ?>
  • Unter system/modules/ajaxrequest erstelle ich die Datei AjaxRequestClass.php, dieser Name muß zum Eintrag in der config.php passen!
    Hier noch der Basisaufbau dieser Datei:

    <?php
    // AjaxRequestClass.php
    class AjaxRequestClass extends System
    	{
    	public function AjaxRequestMethod()
    		{
    		// Zugehörigen Aufruf prüfen, siehe JS-Funktion im FE-Modul
    		if ($this->Input->post('type') == 'ajaxsimple')
    			{
    			$this->import('Database'); // Nötig für Datenbankabfragen
    			// hier kommen die nötigen Funktionalitäten
    			$result['code']="0";
    			$result['msg']="Success";
    			echo json_encode($result);
    			exit;
    			}
    		}
    	}
    ?>
  • Im FE nutze ich dann ein passendes Modul, das meinen Javascript-Code enthält (ich nutze hier jQuery). Der Aufruf geschieht über ein div-Element mit id=“knopf“.
    <script type="text/javascript">
    /* <![CDATA[ */
    // jQuery
    (function($)
    	{
    	$(document).ready(function()
    		{
    		$("#knopf").click(function()
    			{
    			$.ajax({
    				type: "POST",
    				url:  "SimpleAjax.php",
    				data: { type: "ajaxsimple" },
    				success: function(result)
    					{
    					tags = $.parseJSON(result);
    					if (tags['code']=="0")   // nur als Beispiel
    						{
    						// benötigte Aktionen
    						alert(tags["msg"]);
    						}
    					}
    				});
    			});
    		});
    	})(jQuery);
    /* ]]> */
    </script>
  • Jetzt lasse ich den Autoload-Creator arbeiten, der bindet den obigen Hook in’s System ein, danach sollte alles funktionieren.

Das war’s auch schon.

Ich hoffe mal, ich habe alle Codesegmente richtig kopiert.

Veröffentlicht unter IT-Technik | Verschlagwortet mit , , , , , , | Kommentare deaktiviert für Contao 3.1 und Extension simple_ajax – ein Beispiel

Contao 3.1 mit FlexSlider, jQuery und Mootools

Da baue ich gerade eine neue kleine Website mit Contao 3.1.1 und aktiviere jQuery, da ich das lieber mag als die Mootools.

Auf der Seite habe ich den FlexSlider 1.2.2 stable als Erweiterung installiert, der auch wunderbar funktioniert, solange die Mootools nicht aktiviert sind.

Da ich aber die Erweiterung calendarfield nutzen möchte, um im FE auch einen datepicker einzusetzen, muß Mootools aktiviert sein.

Der datepicker funktioniert dann auch prächtig, aber dummerweise funktioniert der FlexSlider jetzt nicht mehr.

Also Google angeworfen, aha, das Problem ist nicht neu.
Anscheinend sollte bei gleichzeitiger Verwendung von jQuery und Mootools  jede JavaScript-Routine wie folgt gekapselt werden:

Bei jQuery das hier:

// jQuery
(function($) {
    // Your code goes here
})(jQuery);

Bei Mootools folgendes:

// MooTools
(function($) {
    // Your code goes here
})(document.id);

Quelle: mootools und jquery mit contao 3

Also mal in den diversen Sourcecodes rumgestöbert, aber beide Erweiterungen benutzen das schon.

Auf der Website bekomme ich aber den Fehler

TypeError: $(...).load is not a function
    $(window).load(function() {

Also wird anscheinend zwar das FlexSlider-Modul richtig abgesichert, aber nicht der vom FlexSlider erzeugte jQuery-Code für die Seite.

Das kann man aber in den template-Dateien des FlexSliders leicht selber korrigieren:

In der unteren Hälfte der template-Datei flexSlider_default.html5 bzw. flexSlider_default.xhtml die beiden Stellen suchen, an denen

$(window).load(function() {

steht. Davor jetzt den nötigen jQuery-Code einfügen:

// jQuery
(function($) {
    $(window).load(function() {

Wichtig: Auf keinen Fall vergessen, die beiden Blöcke auch wieder mit dem Code

})(jQuery);

zu schließen. Das passiert direkt vor dem schließenden </script>-Befehl.

Komplett sieht das also jetzt so aus (passend gekürzt):

<?php if ($configuration['carousel'] == false): ?>
    <script>
    // jQuery
 (function($) {
        $(window).load(function() {
            $('#<?php echo $configuration['alias']; ?>').flexslider({
            ...
            pauseOnAction: true,
            useCSS: false,
            touch: true
            });
        });
    })(jQuery);
    </script>
<?php else: ?>
    <script>
    // jQuery
 (function($) {
        $(window).load(function() {
            $('#<?php echo $configuration['alias']; ?> #carousel').flexslider({
            ...
            pauseOnAction: true,
            controlNav: false,
            animationLoop: true,
            slideshow: true,
            sync: "#<?php echo $configuration['alias']; ?> #carousel"
            });
        });
    })(jQuery);
    </script>
<?php endif; ?>

Ich hoffe sehr, daß ich euch damit weiterhelfen konnte, mich hat dieses Problem doch einige Recherchezeit gekostet.

Veröffentlicht unter IT-Technik | Verschlagwortet mit , , , | Kommentare deaktiviert für Contao 3.1 mit FlexSlider, jQuery und Mootools

OS X auf dem ESXi 5 Server

Das Ziel

OS X in verschiedenen Versionen (Snow Leopard, Lion, Mountain Lion) auf einem ESXi-Server virtualisieren.

Eine solche Virtualisierung ist ja leider von Apple offiziell nicht vorgesehen.

Als zusätzliche Hürde kommt noch dazu, daß sich OS X nur auf Rechnern virtualisieren läßt, die ebenfalls OS X einsetzen. Mit VMWare Fusion läßt sich also durchaus OS X unter OS X virtualisieren, aber das ist nicht immer gewünscht. Mein kleines schwarzes MacBook hat nämlich nicht genug Power, um mehrere OS X gleichzeitig brauchbar zu virtualisieren, und das RAM ist mit 4GB auch etwas knapp.

Also muß OS X auf einen meiner ESXi-Server drauf.

Weiterlesen

Veröffentlicht unter IT-Technik | Verschlagwortet mit , , , , , , , | Hinterlasse einen Kommentar

Autodiscover Funktion in Outlook geht nicht

Für ein Seminar benötige ich eine Outlook 2010 Testumgebung samt Exchange Server.

Also einfach mal alles virtuell aufgesetzt.

Die Installation von Exchange auf einem Windows 2008 R2 Server lief auch ohne Probleme, siehe hier bei Technet.

Die Installation von Raumpostfächern war dank dieser Anleitung auch kein Problem.

Na ja, dann die Benutzer angelegt, auf zwei Testsystemen Outlook 2010 installiert und los geht’s. Soweit klappt auch alles, aber sobald Serverfunktionen wie Abwesenheitsmail (Automatische Antworten), der Zugriff auf freigegebene Kalender oder der Terminplanungsassistent in’s Spiel kamen, gab es Probleme.

Probleme und Fehlermeldungen

  • Bei den Automatischen Antworten kam diese Fehlermeldung:
    Ihre Einstellungen für automatische Antworten können nicht angezeigt werden, da der Server zurzeit nicht verfügbar ist. Versuchen Sie es später erneut.

  • Beim Terminplanungsassistenten stand zu lesen:
    Es können keine Vorschläge angegeben werden, weil Frei/Gebucht-Daten nicht abgerufen werden konnten.
  • Beim Zugriff auf (korrekt) freigegebene Kalender anderer User blieben diese beim Aktualisieren stehen.

Paradoxerweise hat über die Weboberfläche (owa) alles funktioniert.

Also Google anwerfen und recherchieren. Da war dann viel zu Lesen, von virtuellen Ordner und Aktionen, die in der Shell durchzuführen wären, aber diese klangen nicht wirklich erfolgreich, da es auch immer wieder bei manchen nicht geklappt hat.

Also hab ich mal meinen Kopf eingeschaltet und etwas nachgedacht. Wenn es über owa geht, müßte die Funktionalität doch eigentlich auf dem Server soweit in Ordnung sein.

Die Lösung

Was ich aber bei den Recherchen rausbekommen habe war, daß Outlook anscheinend über https-Protokolle Zugriff auf den Exchange-Server nimmt. Also mal von einer Teststation ein ping servername.domain abgesetzt. Und das lief in’s Leere.

Im Windows-Verzeichnis (bei XP unter system32/drivers/etc) also einfach mal die hosts Datei um die IP vom Server und die der Domäne ergänzt, eh voila, es tut.

Vielleichtkann ich ja mit diesem Beitrag dem Einen oder Anderen etwas weiterhelfen, anscheinend geht MS davon aus, daß der Exchange-Server immer in einer „echten“ Domäne liegt und nicht in sowas wie meiner lokalen Testdomain training.local.

Veröffentlicht unter IT-Technik | Verschlagwortet mit , , , , , | Hinterlasse einen Kommentar