diff --git a/hms b/hms deleted file mode 160000 index 2f8e1c2..0000000 --- a/hms +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2f8e1c2a58bc8a3164d30dbfdd3844d0298ad96e diff --git a/hms/__init__.py b/hms/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hms/debug.py b/hms/debug.py new file mode 100644 index 0000000..11c39d1 --- /dev/null +++ b/hms/debug.py @@ -0,0 +1,9 @@ + +DEBUG = 0 + +if DEBUG: + def debug(s): + print "| "+s +else: + def debug(s): + pass diff --git a/hms/generate.py b/hms/generate.py new file mode 100644 index 0000000..fb45085 --- /dev/null +++ b/hms/generate.py @@ -0,0 +1,35 @@ +#!/usr/bin/python + +""" +Support of generated content. +You mark some function with @generates('some_type'). It must return an instance of Generated class. +""" + +generated = dict() + +def generates(cls): + "Mark function that generates content of some class." + def decorator(func): + global generated + name = func.__name__ + if cls in generated: + generated[cls].append(func) + else: + generated[cls] = [func] + return func + return decorator + +def generate(cls): + "Generate all content of given class." + r = [] + for b in generated[cls]: + r.append(b()) + return r + +class Generated(object): + name = "" + description = "" + def show(self): + return "" + def settings(self): + return diff --git a/hms/hms.py b/hms/hms.py new file mode 100644 index 0000000..46e4d11 --- /dev/null +++ b/hms/hms.py @@ -0,0 +1,4 @@ + +import modules +from hooks import * +from generate import * diff --git a/hms/hooks.py b/hms/hooks.py new file mode 100755 index 0000000..d4bd142 --- /dev/null +++ b/hms/hooks.py @@ -0,0 +1,73 @@ +#!/usr/bin/python + +""" +Each `hook' is actually event. You mark some function with @hook decorator, then call that function when you need it. Other modules can intercept that event, marking function with @intercept('hook_name') decorator. When you call function `hook_name()', all functions, marked with @intercept('hook_name'), will be called. +""" + +from debug import * + +hooks = dict() + +def call_hooks(hook,*args): + "Call all functions, intercepting given hook." + global hooks + debug("Test <%s> in %s" % (hook,hooks)) + if hook in hooks: + debug("Calling hooks for %s" % hook) + r = args + for h in hooks[hook]: + prev = r + debug("Calling %s (%s)" % (h,r)) + r = h(*r) + if not r: + return prev + return r + else: + return args + +def hook(func): + "Mark given function as a hook." + global hooks + name = func.__name__ + def wrapper(*args): + r = call_hooks(name,*args) + if type(r) in [str,unicode]: + return func(r) + else: + return func(*r) + wrapper.__name__ = name + wrapper.__doc__ = func.__doc__ + return wrapper + + +def intercept(hook): + "Intercept some hook." + def decorator(func): + global hooks + if hook in hooks: + hooks[hook].append(func) + else: + hooks[hook] = [func] + debug("Now hooks = %s" % hooks) + return func + return decorator + +if __name__ == "__main__": + + @hook + def one(x,y): + print "Op One called: (%s,%s)" % (x,y) + + @intercept('one') + def i1(x,y): + print "Intercepting one." + return (x,y+1) + + @intercept('one') + def i2(x,y): + print "Intercepting one: %s,%s" % (x,y) + return x+3,y + + + print one(2,3) + print hooks diff --git a/hms/modules.py b/hms/modules.py new file mode 100644 index 0000000..61e1db7 --- /dev/null +++ b/hms/modules.py @@ -0,0 +1,59 @@ + +""" +This module imports all mods from modules/ directory. Each module must be a *.py file of form: + +def init(): + ... Here goes definitions. +""" + +import sys +import os +from os.path import dirname,join + +from hooks import * +from generate import * + +MODS_DIR = "modules" +modules = [] +exports = ['export', 'export_as', 'hook', 'intercept', + 'generates', 'generate', 'Generated'] + +def export(func): + "Mark this function to export." + global exports + globals()[func.__name__] = func + exports.append(func.__name__) + return func + +def export_as(obj,name): + "Export some object" + global exports + globals()[name] = obj + exports.append(name) + +@hook +def module_load(mod): + global exports + for n in exports: + setattr(mod,n,globals()[n]) + mod.init() + +def init(): + for w,mod in modules: + module_load(mod) + +for dirpath, dirs, files in os.walk(join(dirname(__file__),MODS_DIR)): + for file in files: + if file[-3:] == ".py": + name = os.path.join(dirpath,file[:-3]) + try: + sys.path.append(os.path.dirname(name)) + module = __import__(os.path.basename(name),{},{},['']) + try: + weight = module.weight + except AttributeError: + weight = 0 + except ImportError,e: + raise ImportError,"Could not import module '%s': %s" % (name,e) + modules.append((weight,module)) +modules.sort() diff --git a/hms/modules/about.py b/hms/modules/about.py new file mode 100644 index 0000000..8a0b066 --- /dev/null +++ b/hms/modules/about.py @@ -0,0 +1,14 @@ + +weight = 1 + +def init(): + + from django.http import HttpResponse + + @intercept('map_url') + def about_page(request): + if isinstance(request,HttpResponse): + return request + if request.path == '/about/': + return HttpResponse("<h1>This page is about Projects system.</h1>") + return request diff --git a/hms/modules/blocks.py b/hms/modules/blocks.py new file mode 100644 index 0000000..910e722 --- /dev/null +++ b/hms/modules/blocks.py @@ -0,0 +1,21 @@ +#encoding: utf-8 + +weight = -10 +def init(): + + block = generates('block') + export_as(block,'block') + + class Block(Generated): + name = "Block" + title = "<none>" + content = "<empty>" + def show(self): + return u"""<div class='block block-%s'> + <h3>%s</h3> + <div class='content'> + %s + </div> + </div>""" % (self.name,self.title,self.content) + + export_as(Block,'Block') diff --git a/hms/modules/bug_chart.py b/hms/modules/bug_chart.py new file mode 100755 index 0000000..3b245f4 --- /dev/null +++ b/hms/modules/bug_chart.py @@ -0,0 +1,73 @@ +#!/usr/bin/python +#encoding: utf-8 + +if __name__ == '__main__': + export = lambda f: f + +def init(): + import os.path + import math + import cairo + + root = "/home/portnov/www/projects/" + labels = [u"Неподтвержденые",u"Подтвержденные",u"В работе",u"Исправлены",u"Неактуальны"] + colors = [(0.75,0.75,1), + (1,0.75,0.75), + (1,1,0.75), + (0.75,1,0.75), + (0.75,0.75,0.75)] + width,height = 200,300 + + def piechart(data,outfile): + surf = cairo.ImageSurface(cairo.FORMAT_ARGB32,width,height) + cx = cairo.Context(surf) + centerx,centery = width/2, width/2 + radius = 0.9*min(width,height)/2 + s = sum(data) + if s == 0: + surf.write_to_png(outfile) + return + n = len(data) + current_angle = 0 + i=0 + cx.select_font_face("DejaVu Sans", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + cx.set_font_size(12) + + for d in data: + angle = float(d)*math.pi*2.0/float(s) + end_angle = current_angle + angle + cx.new_path() + cx.set_source_rgb(*colors[i]) + cx.move_to(centerx,centery) + cx.arc(centerx,centery,radius,current_angle,end_angle) + cx.line_to(centerx,centery) + cx.close_path() + current_angle = end_angle + cx.fill() + cx.set_source_rgb(*colors[i]) + y = height-20*n+20*i + cx.rectangle(15,y,15,15) + cx.fill() + cx.set_source_rgb(0,0,0) + cx.move_to(40,y+12) + cx.show_text(labels[i]) + cx.stroke() + i += 1 + surf.write_to_png(outfile) + + def chart_path(data): + return "/media/charts/chart_" + "_".join(map(str,data)) + ".png" + + @export + def bug_chart(data): + path = chart_path(data) + if not os.path.exists(root+path): + piechart(data,root+path) + return "<img src='%s' alt='Bugs chart'/>" % path + + if __name__ == '__main__': + piechart([0,0,1,0,0],'chart.png') + +if __name__ == '__main__': + init() + diff --git a/hms/modules/last_comments.py b/hms/modules/last_comments.py new file mode 100644 index 0000000..a5e1bdc --- /dev/null +++ b/hms/modules/last_comments.py @@ -0,0 +1,19 @@ +#encoding: utf-8 + +def init(): + + from mgmt.models import Comment + import mgmt.utils + + @block + def last_comments(): + def short_comment(comment): + return u"<li><a href='%s'>%s</a></li>" % (mgmt.utils.get_comment_url(comment),comment.title) + b = Block() + b.name='last_comments' + b.title = u"Последние комментарии" + comments = Comment.objects.order_by('-created')[:10] + b.content = "<ul>\n" + "\n".join(map(short_comment,comments)) + "\n</ul>\n" + return b + + diff --git a/hms/modules/login.py b/hms/modules/login.py new file mode 100644 index 0000000..66d761f --- /dev/null +++ b/hms/modules/login.py @@ -0,0 +1,17 @@ +#encoding: utf-8 + +def init(): + + @block + def login_block(): + b = Block() + b.name = 'login' + b.title = u'Вход в систему' + b.content = u""" + <form action='/login/' method='post'> + <p><label for="username">Логин:</label><input type="text" name="username" value="" id="username"/></p> + <p><label for="password">Пароль:</label><input type="password" name="password" value="" id="password"/></p> + <input type="submit" value="login" /> + <input type='hidden' name='next' value='/'/> + </form>""" + return b diff --git a/hms/modules/menu.py b/hms/modules/menu.py new file mode 100644 index 0000000..09fb21c --- /dev/null +++ b/hms/modules/menu.py @@ -0,0 +1,13 @@ +#encoding: utf-8 + +def init(): + + @export + def menu(request): + m = [] + if request.user.is_authenticated(): + m = settings.MENU_USER + else: + m = settings.MENU_ANONYMOUS + L = ["<a href='%s'>%s</a>" % (l,t) for t,l in m] + return L diff --git a/hms/modules/node.py b/hms/modules/node.py new file mode 100644 index 0000000..41531f1 --- /dev/null +++ b/hms/modules/node.py @@ -0,0 +1,10 @@ + +def init(): + + class Node(object): + author="" + title = "" + content = "" + fields = {} + + export_as(Node,"Node") diff --git a/hms/test.py b/hms/test.py new file mode 100755 index 0000000..d1b31fb --- /dev/null +++ b/hms/test.py @@ -0,0 +1,18 @@ +#!/usr/bin/python + +import os.path + +import modules +from hooks import * +from generate import generate +modules.init() + +@hook +def do_something(s): + print "Doing something with",s + + +print "All modules loaded." + +for b in generate('block'): + print b.show()