root/PyLucidPlugins/pygallery/pygallery.py

Revision 812, 14.6 KB (checked in by JensDiemer, 4 years ago)

first working state... But buggy and not final... Fuck the path handling :(

  • Property svn:keywords set to Rev Date Author
Line 
1#!/usr/bin/python
2# -*- coding: UTF-8 -*-
3
4"""
5Last commit info:
6----------------------------------
7$LastChangedDate$
8$Rev$
9$Author$
10
11Created by Jens Diemer
12
13license:
14    GNU General Public License v2 or above
15    http://www.opensource.org/licenses/gpl-license.php
16"""
17
18__version__ = "$Rev$"
19
20debug = True
21#~ debug = False
22
23
24
25import os, posixpath
26import cgi
27
28
29from PyLucid.components.plugin_cfg import PluginConfig
30from PyLucid.system.BaseModule import PyLucidBaseModule
31
32
33
34
35
36
37class pygallery(PyLucidBaseModule):
38    def __init__(self, *args, **kwargs):
39        super(pygallery, self).__init__(*args, **kwargs)
40
41        self.plugin_cfg = PluginConfig(self.request, self.response)
42
43        self.absolute_base_path = self._get_absolute_path()
44        if debug:
45            self.page_msg("absolute_path:", self.absolute_base_path)
46
47    def lucidFunction(self, function_info):
48        """
49        Aufruf um eine Gallerie in die CMS Seite aufzubauen
50        """
51        self.gallery(function_info)
52
53    #_________________________________________________________________________
54
55    def lucidTag(self):
56        """
57        Dummy, mit Infos
58        """
59        self.setup()
60
61    def setup(self):
62        """
63        Alle existierende Gallerien verwalten
64        """
65        if debug:
66            self.page_msg(self.request.form)
67            self.plugin_cfg.debug()
68
69        if "create" in self.request.form:
70            # Es soll eine neue Gallerie eingerichtet werden
71            self.create_new_gallerie()
72            return
73
74        galleries = []
75        for gallerie, data in self.plugin_cfg["galleries"].iteritems():
76            tag = "<lucidFunction:pygallery>%s</lucidFunction>" % gallerie
77            tag = cgi.escape(tag)
78            galleries.append({
79                "name": gallerie,
80                "lucidFunction": tag,
81                "path": data["path"],
82                "edit_link": self.URLs.actionLink("gallery_config", gallerie)
83            })
84
85        context = {
86            "galleries" : galleries,
87            "url": self.URLs.currentAction(),
88            "base_path": self._get_absolute_path(),
89        }
90        self.page_msg(context)
91        self.templates.write("setup", context)
92
93    #_________________________________________________________________________
94
95    def create_new_gallerie(self):
96        """
97        Erstellt eine neue Gallerie
98        """
99        try:
100            gallery_name = self.request.form["name"]
101        except KeyError, e:
102            self.page_msg.red("Form error. Key '%s' not found." % e)
103            return
104
105        if gallery_name in self.plugin_cfg["galleries"]:
106            self.page_msg.red(
107                "A gallery named '%s' already exists!" % gallery_name
108            )
109            return
110
111        self.plugin_cfg["galleries"][gallery_name] = {
112            "path": None,
113            "cfg": self.plugin_cfg["default_cfg"],
114        }
115        self.page_msg.green("Gallerie created. Please setup.")
116
117        # Direkt die Config Seite aufrufen
118        self.gallery_config([gallery_name])
119
120    #_________________________________________________________________________
121
122    def _rename_gallery(self, old_name, new_name):
123        """
124        Umbenennen einer Gallerie...
125        """
126        if new_name == old_name:
127            # Dolles umbenennen ;)
128            return old_name
129
130        if new_name in self.plugin_cfg["galleries"]:
131            self.page_msg.red("Can't rename gallery! New name exist!")
132            return old_name
133
134        self.plugin_cfg["galleries"][new_name] = \
135                                        self.plugin_cfg["galleries"][old_name]
136
137        del(self.plugin_cfg["galleries"][old_name])
138        self.page_msg.green(
139            "Gallery renamed from %s to %s" % (
140                old_name, new_name
141            )
142        )
143        return new_name
144
145    def gallery_config(self, function_info):
146        """
147        Einstellungen einer bestehenden Gallerie ändern
148        """
149        if debug:
150            self.plugin_cfg.debug()
151            self.page_msg("self.request.form:", self.request.form)
152
153        gallery_name = function_info[0]
154
155        try:
156            gallery_data = self.plugin_cfg["galleries"][gallery_name]
157        except KeyError, e:
158            msg = "Error: Gallery named '%s' unknown! (KeyError: %s)" % (
159                gallery_name, e
160            )
161            self.page_msg.red(msg)
162            return
163
164        if "name" in self.request.form:
165            # Gallerie soll umbenannt werden!
166            new_gallery_name = self.request.form["name"]
167            gallery_name = self._rename_gallery(gallery_name, new_gallery_name)
168
169        absolute_path = self._get_absolute_path()
170
171        def get_paths():
172            result = []
173
174            def dir_filter(path):
175                for filter in self.plugin_cfg["dir_filter"]:
176                    if path.startswith(filter):
177                        return True
178                return False
179
180            abs_path_len = len(absolute_path) + 1
181            for path in os.walk(absolute_path):
182                path = path[0] # Nur Verz. Infos aus os.walk()
183
184                path = path[abs_path_len:]
185                if path == "":
186                    # Erstes Verz.
187                    continue
188                if path.startswith("."):
189                    # Linux versteckte Verz.
190                    continue
191                if dir_filter(path):
192                    # PyLucid Verz.
193                    continue
194
195                result.append(path)
196
197            return result
198
199        context = {
200            #~ "galleries" : galleries,
201            "absolute_path": absolute_path,
202            "current_path": gallery_data["path"],
203            "name": gallery_name,
204
205            "url": self.URLs.actionLink("gallery_config", gallery_name),
206            # Nicht self.URLs.currentAction() nehmen!
207            # Wenn von setup() aufrufgerufen wurde, stimmt der Link nicht!
208        }
209
210        paths = get_paths()
211        if paths == []:
212            self.page_msg.red("No potential directories found!")
213        else:
214            context["paths"] = paths
215
216            if "path" in self.request.form:
217                new_path = self.request.form["path"]
218                if not new_path in paths:
219                    self.page_msg.red("path error!")
220                else:
221                    if gallery_data["path"] != new_path:
222                        gallery_data["path"] = new_path
223                        self.page_msg.green("new gallery path saved.")
224
225        self.page_msg(context)
226        self.templates.write("gallery_config", context)
227
228    #_________________________________________________________________________
229
230    def gallery(self, function_info):
231
232        if isinstance(function_info, basestring):
233            # Direkter Aufruf druch lucidFunction
234            gallery_name = function_info
235            gallery_path = ""
236        else:
237            # User hat ein tieferes Verz. gewählt (_command-Aufruf)
238            gallery_name = function_info[0]
239            gallery_path = "/".join(function_info[1:])
240
241        self.page_msg(
242            "function_info: %s - gallery_name: %s - gallery_path: %s" % (
243                function_info, gallery_name, gallery_path)
244        )
245
246        try:
247            gallery_data = self.plugin_cfg["galleries"][gallery_name]
248        except KeyError, e:
249            msg = "Error: Gallery named '%s' unknown! " % gallery_name
250            if debug:
251                msg += "(KeyError: %s)" % e
252            self.page_msg.red(msg)
253            return
254
255        try:
256            self._setup_workdir(gallery_data["path"], gallery_path)
257        except PathError, e:
258            self.page_msg.red(e)
259            return
260
261        self.cfg = gallery_data["cfg"]
262
263        try:
264            files, dirs, thumbnails = self._read_workdir()
265        except DirReadError, e:
266            self.page_msg.red(e)
267            return
268
269        file_context = self._built_file_context(files, thumbnails)
270        context = {
271            "files": file_context,
272        }
273        dir_context = self._built_dir_context(gallery_name, dirs)
274        context.update(dir_context)
275
276        self.templates.write("gallery", context, debug=True)
277
278    #_________________________________________________________________________
279
280    def _setup_workdir(self, path, gallery_path):
281        self.docRoot = self.URLs["docRoot"]
282
283        path = posixpath.normpath(path)
284        self.relativ_path = posixpath.join(path, gallery_path)
285        self.workdir = posixpath.join(
286            self.absolute_base_path, self.relativ_path
287        )
288        try:
289            self.workdir = self._normpath(self.workdir)
290        except PathError, e:
291            msg = "Path Error!"
292            if debug:
293                msg += " (Workdir: %s - Error: %s)" % (self.workdir, e)
294            raise PathError(msg)
295
296        if debug:
297            self._debug_path()
298
299    def _normpath(self, path):
300        """
301        Normalisiert den Path und gibt diesen zurück
302        -Prüft auf böse Zeichen im Pfad
303        -Prüft ob der Pfad innerhalb von self.absolute_base_path ist
304        -Prüft ob das Ziel wirklich ein existierendes Verz. ist
305        """
306        path = posixpath.normpath(path)
307        if ".." in path or "//" in path or "\\\\" in path:
308            # Da stimmt doch was nicht...
309            raise PathError("bad character in path")
310        if not path.startswith(self.absolute_base_path):
311            raise PathError("Wrong base")
312        if not os.path.isdir(path):
313            raise PathError("Path is not a existing directory.")
314
315        return path
316
317    def _get_absolute_path(self):
318        """
319        Liefert den absoluten basis Pfad zurück
320        """
321        try:
322            doc_root = os.environ["DOCUMENT_ROOT"]
323        except KeyError:
324            doc_root = os.getcwd()
325
326        return doc_root
327
328    def _debug_path(self):
329        self.URLs.debug()
330        self.page_msg("---")
331        self.page_msg("self.absolute_base_path:", self.relativ_path)
332        self.page_msg("self.relativ_path:", self.relativ_path)
333        self.page_msg("self.workdir:", self.workdir)
334        self.page_msg("self.docRoot:", self.docRoot)
335
336    #_________________________________________________________________________
337
338    def _read_workdir(self):
339        """
340        Einlesen des Verzeichnisses self.workdir
341        -filtert direkt die Thumbnails raus
342        """
343        files = []
344        dirs = []
345        thumbnails = {}
346
347        def is_thumb(name, file_name):
348            "Kleine Hilfsfunktion um Thumbnails raus zu filtern"
349            for suffix in self.cfg["thumb_suffix"]:
350                if name[-len(suffix):] == suffix:
351                    # Aktuelle Datei ist ein Thumbnail!
352                    clean_name = name[:-len(suffix)]
353                    thumbnails[clean_name] = file_name
354                    return True
355            return False
356
357        if debug:
358            self.page_msg("read '%s'..." % self.relativ_path)
359
360        try:
361            dirlist = os.listdir(self.workdir)
362        except Exception, e:
363            msg = "Can't read dir."
364            if debug:
365                msg += " (dir: %s, Error: %s)" % (self.workdir, e)
366            raise DirReadError(msg)
367
368        for item in dirlist:
369            abs_path = os.path.join(
370                self.absolute_base_path, self.relativ_path, item
371            )
372            abs_path = os.path.normpath(abs_path)
373            #~ self.page_msg(abs_path)
374
375            if os.path.isdir(abs_path): # Verzeichnis verarbeiten
376                if self.cfg["allow_subdirs"]:
377                    # Unterverz. sollen angezeigt werden
378                    dirs.append(item)
379                continue
380
381            if os.path.isfile(abs_path): # Dateien verarbeiten
382                if item in self.cfg["file_filter"]:
383                    # Datei soll nicht angezeigt werden
384                    continue
385
386                name, ext = posixpath.splitext(item)
387
388                # Thumbnails rausfiltern
389                if is_thumb( name, item ):
390                    # Ist ein Thumbnail -> soll nicht in die files-Liste!
391                    continue
392
393                if ext in self.cfg["ext_whitelist"]:
394                    files.append(item)
395                continue
396
397            # Kein Verz., keine Datei
398            if debug:
399                self.page_msg(
400                    "Skip: %s (is not a file or directory)" % abs_path
401                )
402
403        files.sort()
404        dirs.sort()
405
406        #~ if self.relativ_path != ".":
407            #~ # Nur erweitern, wenn man nicht schon im Hauptverzeichnis ist
408            #~ dirs.insert(0,"..")
409
410        return files, dirs, thumbnails
411
412    def _built_file_context(self, files, thumbnails):
413        """
414        Formt aus den Datelisting Daten den jinja context
415        """
416        def get_thumbnail(base):
417            if base in thumbnails:
418                # Es existiert zu dem Bild ein Thumbnail
419                thumbnail = thumbnails[base]
420            else:
421                # Kein Thumbnail, dann zeigen wir das normale Bild in klein
422                thumbnail = filename
423
424            return posixpath.join(self.docRoot, self.relativ_path, thumbnail)
425
426
427        def get_clean_name(base):
428            result = base
429            for rule in self.cfg["name_filter"]["replace_rules"]:
430                # Alle "replace_rules" Anwenden
431                result = result.replace(rule[0], rule[1])
432
433            if self.cfg["name_filter"]["strip_whitespaces"]:
434                # Leerzeichen bearbeiten
435                result = result.strip(" ")
436                for i in xrange(10):
437                    # Mehrere Leerzeichen, die evtl. bei den "replace_rules"
438                    # entstanden sind, zu einem wandeln
439                    if not "  " in result:
440                        break
441                    result = result.replace("  ", " ")
442
443            return result
444
445
446        context = []
447
448        self.page_msg(thumbnails)
449        for filename in files:
450            base, ext = os.path.splitext(filename)
451            if not ext in self.cfg["ext_whitelist"]:
452                continue
453
454            file_info = {}
455
456            # Adresse zum Thumbnail
457            file_info["src"] = get_thumbnail(base)
458
459            # Name des Bildes
460            file_info["name"] = get_clean_name(base)
461
462            context.append(file_info)
463
464        return context
465
466    def _built_dir_context(self, gallery_name, dirs):
467        dir_info = []
468        for dirname in dirs:
469            dir_info.append({
470                "href": self.URLs.actionLink("gallery",(gallery_name,dirname)),
471                "name": dirname
472            })
473
474        context = {
475            "back_href": "..",
476            "dirs": dir_info,
477        }
478
479        return context
480
481
482class PathError(Exception):
483    """ Mit dem Path stimmt was nicht """
484    pass
485
486class DirReadError(Exception):
487    """ Workdir kann nicht eingelesen werden """
488    pass
489
490
Note: See TracBrowser for help on using the browser.