1 | # -*- coding: utf-8 -*- |
---|
2 | # |
---|
3 | # Copyright (C) 2012 Steffen Hoffmann <hoff.st@web.de> |
---|
4 | # All rights reserved. |
---|
5 | # |
---|
6 | # This software is licensed as described in the file COPYING, which |
---|
7 | # you should have received as part of this distribution. |
---|
8 | # |
---|
9 | # Author: Steffen Hoffmann <hoff.st@web.de> |
---|
10 | |
---|
11 | from genshi.builder import Markup, tag |
---|
12 | |
---|
13 | from trac.core import Component, implements |
---|
14 | from trac.perm import PermissionSystem |
---|
15 | from trac.util.compat import sorted |
---|
16 | from trac.web.chrome import Chrome |
---|
17 | from trac.wiki.api import IWikiMacroProvider, WikiSystem, parse_args |
---|
18 | from trac.wiki.formatter import format_to_oneliner |
---|
19 | |
---|
20 | from acct_mgr.admin import fetch_user_data |
---|
21 | from acct_mgr.api import AccountManager, CommonTemplateProvider, _ |
---|
22 | from acct_mgr.guard import AccountGuard |
---|
23 | from acct_mgr.util import get_pretty_dateinfo |
---|
24 | |
---|
25 | |
---|
26 | class AccountManagerWikiMacros(CommonTemplateProvider): |
---|
27 | """Provides wiki macros related to Trac accounts/authenticated users.""" |
---|
28 | |
---|
29 | implements(IWikiMacroProvider) |
---|
30 | |
---|
31 | # IWikiMacroProvider |
---|
32 | |
---|
33 | def get_macros(self): |
---|
34 | yield 'ProjectStats' |
---|
35 | yield 'UserQuery' |
---|
36 | |
---|
37 | def get_macro_description(self, name): |
---|
38 | if name == 'ProjectStats': |
---|
39 | return """Wiki macro listing some generic Trac statistics. |
---|
40 | |
---|
41 | This macro accepts a comma-separated list of keyed parameters, in the form |
---|
42 | "key=value". Valid keys: |
---|
43 | * '''wiki''' -- statistics for TracWiki, values: |
---|
44 | * ''count'' -- show wiki page count |
---|
45 | * '''prefix''' -- use with ''wiki'' key: only names that start with that |
---|
46 | prefix are included |
---|
47 | |
---|
48 | 'count' is also recognized without prepended key name. |
---|
49 | """ |
---|
50 | |
---|
51 | elif name == 'UserQuery': |
---|
52 | return """Wiki macro listing users that match certain criteria. |
---|
53 | |
---|
54 | This macro accepts a comma-separated list of keyed parameters, in the form |
---|
55 | "key=value". Valid keys: |
---|
56 | * '''perm''' -- show only that users, a permission action given by ''value'' |
---|
57 | has been granted to |
---|
58 | * '''locked''' -- retrieve users, who's account has/has not been locked |
---|
59 | depending on boolean value |
---|
60 | * '''format''' -- output style: 'count', 'list' or comma-separated values |
---|
61 | (default) |
---|
62 | * '''nomatch''' -- replacement wiki markup that is displayed, if there's |
---|
63 | no match and output style isn't 'count' either |
---|
64 | |
---|
65 | 'count' is also recognized without prepended key name. Other non-keyed |
---|
66 | parameters are: |
---|
67 | * '''locked''' -- alias for 'locked=True' |
---|
68 | * '''visit''' -- show a list of accounts with last-login information, only |
---|
69 | available in table format |
---|
70 | * '''name''' -- forces replacement of maching username with their |
---|
71 | corresponding full names, if available; adds a full names column if combined |
---|
72 | with 'visit' |
---|
73 | * '''email''' -- append email address to usernames, if available |
---|
74 | |
---|
75 | Requires `USER_VIEW` permission for output in any format other then 'count'. |
---|
76 | A misc placeholder with this statement is presented to unprivileged users. |
---|
77 | """ |
---|
78 | |
---|
79 | def expand_macro(self, formatter, name, content): |
---|
80 | env = formatter.env |
---|
81 | req = formatter.req |
---|
82 | if not content: |
---|
83 | args = [] |
---|
84 | kw = {} |
---|
85 | else: |
---|
86 | args, kw = parse_args(content) |
---|
87 | if name == 'ProjectStats': |
---|
88 | if 'wiki' in kw.keys(): |
---|
89 | prefix = 'prefix' in kw.keys() and kw['prefix'] or None |
---|
90 | wiki = WikiSystem(env) |
---|
91 | if kw['wiki'] == 'count' or 'count' in args: |
---|
92 | return tag(sum(1 for page in wiki.get_pages(prefix))) |
---|
93 | elif name == 'UserQuery': |
---|
94 | msg_no_perm = tag.p(Markup(_("(required %(perm)s missing)", |
---|
95 | perm=tag.strong('USER_VIEW'))), |
---|
96 | class_='hint') |
---|
97 | users = [] |
---|
98 | if 'perm' in kw.keys(): |
---|
99 | perm_sys = PermissionSystem(self.env) |
---|
100 | users = perm_sys.get_users_with_permission(kw['perm'].upper()) |
---|
101 | else: |
---|
102 | acct_mgr = AccountManager(env) |
---|
103 | users = list(set(acct_mgr.get_users())) |
---|
104 | if 'locked' in kw.keys() or 'locked' in args: |
---|
105 | guard = AccountGuard(env) |
---|
106 | locked = [] |
---|
107 | for user in users: |
---|
108 | if guard.user_locked(user): |
---|
109 | locked.append(user) |
---|
110 | if kw.get('locked', 'True').lower() in ('true', 'yes', '1'): |
---|
111 | users = locked |
---|
112 | else: |
---|
113 | users = list(set(users) - set(locked)) |
---|
114 | elif 'visit' in kw.keys() or 'visit' in args: |
---|
115 | if not 'USER_VIEW' in req.perm: |
---|
116 | return msg_no_perm |
---|
117 | cols = [] |
---|
118 | data = {} |
---|
119 | data['accounts'] = fetch_user_data(env, req) |
---|
120 | data['cls'] = 'wiki' |
---|
121 | for col in ('email', 'name'): |
---|
122 | if col in args: |
---|
123 | cols.append(col) |
---|
124 | data['cols'] = cols |
---|
125 | data['pretty_date'] = get_pretty_dateinfo(env, req) |
---|
126 | return Chrome(env).render_template( |
---|
127 | req, 'user_table.html', data, 'text/html', True) |
---|
128 | if kw.get('format') == 'count' or 'count' in args: |
---|
129 | return tag(len(users)) |
---|
130 | if not 'USER_VIEW' in req.perm: |
---|
131 | return msg_no_perm |
---|
132 | if 'email' in args or 'name' in args: |
---|
133 | # Replace username with full name, add email if available. |
---|
134 | for username, name, email in self.env.get_known_users(): |
---|
135 | if username in users: |
---|
136 | if not 'name' in args or name is None: |
---|
137 | name = username |
---|
138 | if 'email' in args and email is not None: |
---|
139 | email = ''.join(['<', email, '>']) |
---|
140 | name = ' '.join([name, email]) |
---|
141 | if not username == name: |
---|
142 | users.pop(users.index(username)) |
---|
143 | users.append(name) |
---|
144 | if not users and 'nomatch' in kw.keys(): |
---|
145 | return format_to_oneliner(env, formatter.context, |
---|
146 | kw['nomatch']) |
---|
147 | users = sorted(users) |
---|
148 | if kw.get('format') == 'list': |
---|
149 | return tag.ul([tag.li(Chrome(env).format_author(req, user)) |
---|
150 | for user in users]) |
---|
151 | else: |
---|
152 | # Default output format: comma-separated list. |
---|
153 | return tag(', '.join([Chrome(env).format_author(req, user) |
---|
154 | for user in users])) |
---|