diff --git a/.gitignore b/.gitignore index c9e4520..fdbda5b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,5 @@ *.swp *.pyc *.log -mgmt/hms -media/charts +media/charts/*.png +*.tar.gz diff --git a/media/js/markitup/skins/markitup/style.css b/media/js/markitup/skins/markitup/style.css index 6f3a3c7..42e59a3 100644 --- a/media/js/markitup/skins/markitup/style.css +++ b/media/js/markitup/skins/markitup/style.css @@ -12,7 +12,6 @@ text-decoration:none; } .markItUp { - width:700px; margin:5px 0 5px 0; border:5px solid #F5F5F5; } @@ -23,10 +22,11 @@ font:11px Verdana, Arial, Helvetica, sans-serif; } .markItUpEditor { - font:12px 'Courier New', Courier, monospace; + width: 95%; + font-family: monospace; + font-size: medium; padding:5px 5px 5px 35px; border:3px solid #3C769D; - width:643px; height:320px; background-image:url(images/bg-editor.png); background-repeat:no-repeat; @@ -38,7 +38,7 @@ overflow:auto; background-color:#FFFFFF; border:1px solid #3C769D; - width:99.9%; +/* width:99.9%;*/ height:300px; margin:5px 0; } @@ -121,7 +121,7 @@ display:block; padding-left:0px; text-indent:0; - width:120px; +/* width:120px; */ padding:5px 5px 5px 25px; background-position:2px 50%; } @@ -145,4 +145,4 @@ .wiki .markItUpEditor, .dotclear .markItUpEditor { background-image:url(images/bg-editor-wiki.png); -} \ No newline at end of file +} diff --git a/media/tarballs/projects-228d60b-228d60b.tar.gz b/media/tarballs/projects-228d60b-228d60b.tar.gz deleted file mode 100644 index c75348b..0000000 Binary files a/media/tarballs/projects-228d60b-228d60b.tar.gz and /dev/null differ diff --git a/mgmt/hms/.gitignore b/mgmt/hms/.gitignore new file mode 100644 index 0000000..4e72520 --- /dev/null +++ b/mgmt/hms/.gitignore @@ -0,0 +1,3 @@ +.*.swp +*.swp +*.pyc diff --git a/mgmt/hms/__init__.py b/mgmt/hms/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mgmt/hms/debug.py b/mgmt/hms/debug.py new file mode 100644 index 0000000..11c39d1 --- /dev/null +++ b/mgmt/hms/debug.py @@ -0,0 +1,9 @@ + +DEBUG = 0 + +if DEBUG: + def debug(s): + print "| "+s +else: + def debug(s): + pass diff --git a/mgmt/hms/generate.py b/mgmt/hms/generate.py new file mode 100644 index 0000000..fb45085 --- /dev/null +++ b/mgmt/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/mgmt/hms/hms.py b/mgmt/hms/hms.py new file mode 100644 index 0000000..46e4d11 --- /dev/null +++ b/mgmt/hms/hms.py @@ -0,0 +1,4 @@ + +import modules +from hooks import * +from generate import * diff --git a/mgmt/hms/hooks.py b/mgmt/hms/hooks.py new file mode 100755 index 0000000..f991423 --- /dev/null +++ b/mgmt/hms/hooks.py @@ -0,0 +1,72 @@ +#!/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 + 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/mgmt/hms/modules.py b/mgmt/hms/modules.py new file mode 100644 index 0000000..61e1db7 --- /dev/null +++ b/mgmt/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/mgmt/hms/modules/blocks.py b/mgmt/hms/modules/blocks.py new file mode 100644 index 0000000..910e722 --- /dev/null +++ b/mgmt/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/mgmt/hms/modules/bug_chart.py b/mgmt/hms/modules/bug_chart.py new file mode 100755 index 0000000..3b245f4 --- /dev/null +++ b/mgmt/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/mgmt/hms/modules/last_comments.py b/mgmt/hms/modules/last_comments.py new file mode 100644 index 0000000..702286c --- /dev/null +++ b/mgmt/hms/modules/last_comments.py @@ -0,0 +1,27 @@ +#encoding: utf-8 + +def init(): + + from mgmt.models import Comment + + @block + def last_comments(): + def short_comment(comment): + def get_url(comment): + type = comment.object_type + id = comment.object_id + if type=='Project': + return "/projects/%s/#comment-%s" % (id,comment.id) + if type=='Bug': + return "/bugs/%s/#comment-%s" % (id,comment.id) + if type=='Document': + return "/docs/%d/#comment-%s" % (id,comment.id) + return "<li><a href='%s'>%s</a></li>" % (get_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/mgmt/hms/modules/login.py b/mgmt/hms/modules/login.py new file mode 100644 index 0000000..66d761f --- /dev/null +++ b/mgmt/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/mgmt/hms/modules/menu.py b/mgmt/hms/modules/menu.py new file mode 100644 index 0000000..09fb21c --- /dev/null +++ b/mgmt/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/mgmt/hms/modules/node.py b/mgmt/hms/modules/node.py new file mode 100644 index 0000000..41531f1 --- /dev/null +++ b/mgmt/hms/modules/node.py @@ -0,0 +1,10 @@ + +def init(): + + class Node(object): + author="" + title = "" + content = "" + fields = {} + + export_as(Node,"Node") diff --git a/mgmt/hms/modules/test1.py b/mgmt/hms/modules/test1.py new file mode 100644 index 0000000..dccef22 --- /dev/null +++ b/mgmt/hms/modules/test1.py @@ -0,0 +1,15 @@ + +def init(): + print "Module <Test> imported." + + @intercept('do_something') + def func(s): + print "Intercepted." + return s + + @hook + def my_hook(): + print "Some event." + + + my_hook() diff --git a/mgmt/hms/modules/test2.py b/mgmt/hms/modules/test2.py new file mode 100644 index 0000000..f5d3524 --- /dev/null +++ b/mgmt/hms/modules/test2.py @@ -0,0 +1,7 @@ + +def init(): + print "Test 2 loaded" + + @intercept('my_hook') + def on_hook(): + print "<myhook> intercepted." diff --git a/mgmt/hms/modules/testblock.py b/mgmt/hms/modules/testblock.py new file mode 100644 index 0000000..be49e4f --- /dev/null +++ b/mgmt/hms/modules/testblock.py @@ -0,0 +1,10 @@ + +def init(): + + @block + def testblk(): + b = Block() + b.name = "testblk" + b.title = "Test block" + b.content = "Content of test block." + return b diff --git a/mgmt/hms/test.py b/mgmt/hms/test.py new file mode 100755 index 0000000..d1b31fb --- /dev/null +++ b/mgmt/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()