def remove_history(save): print('Telephone numbers:') for user in Es.users(): remove_history_item(user, 'telephones', 'telephone', 'number', save=save) print('\nEmail addresses:') for user in Es.users(): remove_history_item(user, 'emailAddresses', 'email', 'email', save=save) print('\nPost addresses:') for user in Es.users(): remove_history_item(user, 'addresses', 'address', None, save=save)
def api_users(request): if not request.REQUEST['key'] in settings.ALLOWED_API_KEYS: raise PermissionDenied ret = {} for m in Es.users(): ret[str(m.name)] = m.full_name return HttpResponse(json.dumps(ret), mimetype="text/json")
def main(): for e in Es.users(): # Remove empty study entries if e._data['studies']: study = e._data['studies'][0] if (study['study'] is None and study['number'] is None and study['institute'] is None and len(e._data['studies']) == 1): e._data['studies'] = [] e.save() # Remove empty address entries if e._data['addresses']: address = e._data['addresses'][0] if (not address['street'] and not address['city'] and not address['number'] and len(e._data['addresses']) == 1): e._data['addresses'] = [] e.save() # Remove empty telephone entries if e._data['telephones']: address = e._data['telephones'][0] if (not address['number'] and len(e._data['telephones']) == 1): e._data['telephones'] = [] e.save()
def generate_openvpn_zips(giedo): for u in Es.users(): if not u.is_active: continue if not os.path.isfile(os.path.join(settings.VPN_INSTALLER_STORAGE, 'openvpn-config-%s.zip' % str(u.name))): _create_zip(u)
def main(): leden = Es.by_name('leden') lut = {} id2name = {} for m in Es.users(): if not m.name: continue lut[str(m.name)] = set() id2name[m._id] = str(m.name) max_q = Es.date_to_year(Es.now()) * 4 for q in range(1, max_q + 1): start, end = Es.quarter_to_range(q) for m in leden.get_rrelated(_from=start, until=end, how=None, deref_who=False, deref_with=False, deref_how=False): lut[id2name[m['who']]].add(q) for i, name in enumerate(sorted(six.itervalues(id2name))): if i % 20 == 0: print() print('%20s %s' % ( 'year', ' '.join([str(((q - 1) / 4) + 1).ljust(7) for q in range(1, max_q + 1, 4)]) )) print('%20s %s' % ( 'quarter', ' '.join([str(((q - 1) % 4) + 1) for q in range(1, max_q + 1)]) )) print('%-20s %s' % ( name, ' '.join(['*' if q in lut[name] else ' ' for q in range(1, max_q + 1)]) ))
def fiscus_debtmail(request): if 'fiscus' not in request.user.cached_groups_names: raise PermissionDenied data = dict([(n, {'debt': Decimal(debt)}) for (n, debt) in giedo.fin_get_debitors()]) for user in Es.users(): name = user.full_name if name in data: data[name]['user'] = user ctx = { 'BASE_URL': settings.BASE_URL, 'quaestor': fin.quaestor(), 'account_number': settings.BANK_ACCOUNT_NUMBER, 'account_holder': settings.BANK_ACCOUNT_HOLDER, } if request.method == 'POST' and 'debitor' in request.POST: users_to_email = request.POST.getlist('debitor') for user_name in users_to_email: user = Es.by_name(user_name) ctx['first_name'] = user.first_name, ctx['debt'] = data[user.full_name]['debt'] try: render_then_email("leden/debitor.mail.txt", to=user, ctx=ctx, cc=[], # ADD penningmeester from_email=ctx['quaestor']['email'], reply_to=ctx['quaestor']['email']) messages.info( request, _("Email gestuurd naar %s.") % user_name) except Exception as e: messages.error(request, _("Email naar %(user)s faalde: %(e)s.") % {'user': user_name, 'e': repr(e)}) # get a sample of the email that will be sent for the quaestor's review. email = "" email_template = get_template('leden/debitor.mail.txt') ctx['first_name'] = '< Naam >' ctx['debt'] = '< Debet >' context = Context(ctx) for node in email_template: if isinstance(node, BlockNode) and node.name == "plain": email = node.render(context) break return render_to_response('leden/fiscus_debtmail.html', {'data': data, 'email': email}, context_instance=RequestContext(request))
def generate_unix_map(giedo): ret = {'groups': {}, 'users': {}} dt_now = now() # Get all users ulut = dict() for u in Es.users(): if not u.got_unix_user: continue ulut[u._id] = u ret['users'][str(u.name)] = { 'full_name': u.full_name, 'expire_date': DT_MIN.strftime('%Y-%m-%d')} member_relations_grouped = dict() for rel in Es.query_relations(_with=Es.by_name('leden'), until=dt_now): if rel['who'] not in member_relations_grouped: member_relations_grouped[rel['who']] = [] member_relations_grouped[rel['who']].append(rel) for user_id, relations in member_relations_grouped.items(): latest = max(relations, key=lambda x: x['until']) ret['users'][str(ulut[user_id].name)]['expire_date'] = ( latest['until'].strftime('%Y-%m-%d')) # Get all groups and create a look-up-table for group membership gs = tuple(Es.groups()) mrels = Es.query_relations(how=None, _with=gs, _from=dt_now, until=dt_now) mlut = dict() for g in gs: mlut[g._id] = [] for mrel in mrels: mlut[mrel['with']].append(mrel['who']) # Flatten out group membership. For instance: if Giedo is in Kasco # and Kasco is in Boekenlezers, then Giedo is also in the Boekenlezers # unix group. # But first split the mlut graph into a group and a non-group subgraph. mlut_g = {} # { <group> : <members that are groups> } mlut_ng = {} # { <group> : <members that are not groups> } for g_id in mlut: mlut_g[g_id] = [c for c in mlut[g_id] if c in mlut] mlut_ng[g_id] = [c for c in mlut[g_id] if c not in mlut] mlut_g_tc = tc(mlut_g) # transitive closure # Generate the { <group> : <indirect non-group members> } graph memb_graph = {} for g in gs: if not g.got_unix_group: continue memb_graph[g._id] = set(mlut_ng[g._id]) for h_id in mlut_g_tc[g._id]: memb_graph[g._id].update(mlut_ng[h_id]) # Fill the return map for g in gs: if not g.got_unix_group: continue ret['groups'][str(g.name)] = [str(ulut[c].name) for c in memb_graph[g._id] if c in ulut] return ret
def generate_unix_map(giedo): ret = {'groups': {}, 'users': {}} dt_now = now() # Get all users ulut = dict() for u in Es.users(): if not u.got_unix_user: continue ulut[u._id] = u ret['users'][str(u.name)] = { 'full_name': u.full_name, 'expire_date': DT_MIN.strftime('%Y-%m-%d')} member_relations_grouped = dict() for rel in Es.query_relations(_with=Es.by_name('leden'), until=dt_now): if rel['who'] not in member_relations_grouped: member_relations_grouped[rel['who']] = [] member_relations_grouped[rel['who']].append(rel) for user_id, relations in member_relations_grouped.items(): latest = max(relations, key=lambda x: x['until']) ret['users'][str(ulut[user_id].name)]['expire_date'] \ = latest['until'].strftime('%Y-%m-%d') # Get all groups and create a look-up-table for group membership gs = tuple(Es.groups()) mrels = Es.query_relations(how=None, _with=gs, _from=dt_now, until=dt_now) mlut = dict() for g in gs: mlut[g._id] = [] for mrel in mrels: mlut[mrel['with']].append(mrel['who']) # Flatten out group membership. For instance: if Giedo is in Kasco # and Kasco is in Boekenlezers, then Giedo is also in the Boekenlezers # unix group. # But first split the mlut graph into a group and a non-group subgraph. mlut_g = {} # { <group> : <members that are groups> } mlut_ng = {} # { <group> : <members that are not groups> } for g_id in mlut: mlut_g[g_id] = [c for c in mlut[g_id] if c in mlut] mlut_ng[g_id] = [c for c in mlut[g_id] if c not in mlut] mlut_g_tc = tc(mlut_g) # transitive closure # Generate the { <group> : <indirect non-group members> } graph memb_graph = {} for g in gs: if not g.got_unix_group: continue memb_graph[g._id] = set(mlut_ng[g._id]) for h_id in mlut_g_tc[g._id]: memb_graph[g._id].update(mlut_ng[h_id]) # Fill the return map for g in gs: if not g.got_unix_group: continue ret['groups'][str(g.name)] = [str(ulut[c].name) for c in memb_graph[g._id] if c in ulut] return ret
def fiscus_debtmail(request): if 'fiscus' not in request.user.cached_groups_names: raise PermissionDenied data = dict([(n, { 'debt': Decimal(debt) }) for (n, debt) in giedo.fin_get_debitors()]) for user in Es.users(): name = user.full_name if name in data: data[name]['user'] = user ctx = { 'BASE_URL': settings.BASE_URL, 'quaestor': fin.quaestor(), 'account_number': settings.BANK_ACCOUNT_NUMBER, 'account_holder': settings.BANK_ACCOUNT_HOLDER, } if request.method == 'POST' and 'debitor' in request.POST: users_to_email = request.POST.getlist('debitor') for user_name in users_to_email: user = Es.by_name(user_name) ctx['first_name'] = user.first_name ctx['debt'] = data[user.full_name]['debt'] try: render_then_email( 'leden/debitor.mail.html', to=user, ctx=ctx, cc=[], # ADD penningmeester from_email=ctx['quaestor']['email'], reply_to=ctx['quaestor']['email']) messages.info(request, _("Email gestuurd naar %s.") % user_name) except Exception as e: messages.error( request, _("Email naar %(user)s faalde: %(e)s.") % { 'user': user_name, 'e': repr(e) }) # get a sample of the email that will be sent for the quaestor's review. ctx['first_name'] = '< Naam >' ctx['debt'] = '< Debet >' email = render_message('leden/debitor.mail.html', ctx)['html'] return render(request, 'leden/fiscus_debtmail.html', { 'data': data, 'email': email })
def find_name_for_user(first_name, last_name): """ Given the first and the last name of a user, find a free name """ def clean(s, last_name=False, capitalize_tussenvoegsels=False): """ Cleans a first or last name. We do some extra things for last names and optionally capitalize letters that came from tussenvoegsels. """ if last_name and ',' in s: bits = s.split(',', 2) s = bits[1] + ' ' + bits[0] s = unidecode.unidecode(s).lower() s = ''.join((x for x in s if x in settings.USERNAME_CHARS)) if last_name: s = s.replace('van ', 'V ') s = s.replace('der ', 'D ') s = s.replace('de ', 'D ') s = s.replace('den ', 'D ') if not capitalize_tussenvoegsels: s = s.lower() return s.replace(' ', '') names = Es.names() fn = clean(first_name) ln_ctv = clean(last_name, last_name=True, capitalize_tussenvoegsels=True) ln = clean(last_name, last_name=True) # Others users with this firstname users_with_same_fn = [ u for u in Es.users() if u.first_name and clean(u.first_name) == fn ] # Try first_name or first_name with a few letters of the last_name appended for i in range(len(ln) + 1): n = fn + ln[:i] # Don't try giedov, but directly giedovdm if the name is derived # from `Giedo van der Meer'. if i and ln_ctv[:i][-1].isupper(): continue if n in names: continue # Recall `Giedo Jansen' has the username `giedo'. Suppose there is # a new member called `Giedo Joosten'. In this case we want to give # him the username `giedojo' instead of `giedoj'. ok = True for u in users_with_same_fn: un = clean(u.first_name) + clean(u.last_name, last_name=True) if un.startswith(n): ok = False break if ok: return n # Last resort: try <first_name><last_name><i> for i in {2,3,...} i = 1 while True: i += 1 n = fn + ln + str(i) if n not in names: return n
def api_users(request): verified_key = False for key in settings.ALLOWED_API_KEYS: if constant_time_compare(request.REQUEST['key'], key): verified_key = True if not verified_key: raise PermissionDenied ret = {} for m in Es.users(): ret[str(m.name)] = m.full_name return HttpResponse(json.dumps(ret), content_type="text/json")
def find_name_for_user(first_name, last_name): """ Given the first and the last name of a user, find a free name """ def clean(s, last_name=False, capitalize_tussenvoegsels=False): """ Cleans a first or last name. We do some extra things for last names and optionally capitalize letters that came from tussenvoegsels. """ if last_name and ',' in s: bits = s.split(',', 2) s = bits[1] + ' ' + bits[0] s = unidecode.unidecode(s).lower() s = filter(lambda x: x in settings.USERNAME_CHARS + ' ', s) if last_name: s = s.replace('van ', 'V ') s = s.replace('der ', 'D ') s = s.replace('de ', 'D ') s = s.replace('den ', 'D ') if not capitalize_tussenvoegsels: s = s.lower() return s.replace(' ', '') names = Es.names() fn = clean(first_name) ln_ctv = clean(last_name, last_name=True, capitalize_tussenvoegsels=True) ln = clean(last_name, last_name=True) # Others users with this firstname users_with_same_fn = [u for u in Es.users() if u.first_name and clean(u.first_name) == fn] # Try first_name or first_name with a few letters of the last_name appended for i in xrange(len(ln)+1): n = fn + ln[:i] # Don't try giedov, but directly giedovdm if the name is derived # from `Giedo van der Meer'. if i and ln_ctv[:i][-1].isupper(): continue if n in names: continue # Recall `Giedo Jansen' has the username `giedo'. Suppose there is # a new member called `Giedo Joosten'. In this case we want to give # him the username `giedojo' instead of `giedoj'. ok = True for u in users_with_same_fn: un = clean(u.first_name) + clean(u.last_name, last_name=True) if un.startswith(n): ok = False break if ok: return n # Last resort: try <first_name><last_name><i> for i in {2,3,...} i = 1 while True: i += 1 n = fn + ln + str(i) if n not in names: return n
def _entity_detail(request, e): def _cmp(x,y): r = Es.relation_cmp_until(y,x) if r: return r r = cmp(unicode(x['with'].humanName), unicode(y['with'].humanName)) if r: return r r = cmp(unicode(x['how'].humanName) if x['how'] else None, unicode(y['how'].humanName) if y['how'] else None) if r: return r return Es.relation_cmp_from(x,y) def _rcmp(x,y): r = Es.relation_cmp_until(y,x) if r: return r r = cmp(unicode(x['how'].humanName) if x['how'] else None, unicode(y['how'].humanName) if y['how'] else None) if r: return r r = cmp(unicode(x['who'].humanName), unicode(y['who'].humanName)) if r: return r return Es.relation_cmp_from(x,y) related = sorted(e.get_related(), cmp=_cmp) rrelated = sorted(e.get_rrelated(), cmp=_rcmp) for r in chain(related, rrelated): r['may_end'] = Es.user_may_end_relation(request.user, r) r['id'] = r['_id'] r['until_year'] = (None if r['until'] is None else Es.date_to_year(r['until'])) r['virtual'] = Es.relation_is_virtual(r) tags = [t.as_primary_type() for t in e.get_tags()] ctx = {'related': related, 'rrelated': rrelated, 'now': now(), 'tags': sorted(tags, Es.entity_cmp_humanName), 'object': e} # Is request.user allowed to add (r)relations? if ('secretariaat' in request.user.cached_groups_names and (e.is_group or e.is_user)): groups = [g for g in Es.groups() if not g.is_virtual] groups.sort(cmp=lambda x,y: cmp(unicode(x.humanName), unicode(y.humanName))) users = sorted(Es.users(), cmp=Es.entity_cmp_humanName) brands = sorted(Es.brands(), cmp=Es.entity_cmp_humanName) ctx.update({'users': users, 'brands': brands, 'groups': groups, 'may_add_related': True, 'may_add_rrelated': True}) if e.is_tag: ctx.update({'tag_bearers': sorted(e.as_tag().get_bearers(), cmp=Es.entity_cmp_humanName)}) return ctx
def _sync_villanet(self): ret = self.villanet_request({'action': 'listUsers'}) if not ret[0]: return ret = json.loads(ret[1]) users = dict() ulut = dict() for u in Es.users(): ulut[u._id] = str(u.name) member_relations_grouped = dict() for rel in Es.query_relations(_with=Es.by_name('leden'), until=now()): if rel['who'] not in member_relations_grouped: member_relations_grouped[rel['who']] = [] member_relations_grouped[rel['who']].append(rel) for user_id, relations in member_relations_grouped.items(): latest = max(relations, key=lambda x: x['until']) users[ulut[user_id]] = latest['until'].strftime('%Y-%m-%d') vn = set(ret.keys()) kn = set(users.keys()) dt_max = settings.DT_MAX.strftime('%Y-%m-%d') for name in kn - vn: data = { 'username': name, 'password': self.villanet_encrypt_password(pseudo_randstr(16)), } if users[name] != dt_max: data['till'] = users[name] pc = Es.PushChange({ 'system': 'villanet', 'action': 'addUser', 'data': data }) pc.save() for name in vn - kn: logging.info("Stray user %s" % name) for name in vn & kn: remote = (ret[name]['till'][:10] if ret[name]['till'] is not None else '') local = users[name] if users[name] != dt_max else '' if remote != local: pc = Es.PushChange({ 'system': 'villanet', 'action': 'changeUser', 'data': { 'username': name, 'till': local } }) pc.save() self.push_changes_event.set()
def _sync_villanet(self): if not settings.VILLANET_SECRET_API_KEY: logging.warn("VILLANET_SECRET_API_KEY not set") return ret = self.villanet_request({'action': 'listUsers'}) if not ret[0]: return ret = json.loads(ret[1]) users = dict() ulut = dict() for u in Es.users(): ulut[u._id] = str(u.name) member_relations_grouped = dict() for rel in Es.query_relations(_with=Es.by_name('leden'), until=now()): if rel['who'] not in member_relations_grouped: member_relations_grouped[rel['who']] = [] member_relations_grouped[rel['who']].append(rel) for user_id, relations in member_relations_grouped.items(): latest = max(relations, key=lambda x: x['until']) users[ulut[user_id]] = latest['until'].strftime('%Y-%m-%d') vn = set(ret.keys()) kn = set(users.keys()) dt_max = settings.DT_MAX.strftime('%Y-%m-%d') for name in kn - vn: data = { 'username': name, 'password': self.villanet_encrypt_password( pseudo_randstr(16)), } if users[name] != dt_max: data['till'] = users[name] pc = Es.PushChange({'system': 'villanet', 'action': 'addUser', 'data': data}) pc.save() for name in vn - kn: logging.info("Stray user %s" % name) for name in vn & kn: remote = (ret[name]['till'][:10] if ret[name]['till'] is not None else '') local = users[name] if users[name] != dt_max else '' if remote != local: pc = Es.PushChange({'system': 'villanet', 'action': 'changeUser', 'data': { 'username': name, 'till': local }}) pc.save() self.push_changes_event.set()
def find_name_for_user(first_name, last_name): """ Given the first and the last name of a user, find a free name """ names = Es.names() def clean(s): return filter(lambda x: x in settings.USERNAME_CHARS, s.lower()) def clean_ln(s): if ',' in s: bits = s.split(',', 2) s = bits[1] + ' ' + bits[0] s = s.lower() s = s.replace('van ', 'v ') s = s.replace('de ', 'd ') s = s.replace('der ', 'd ') s = s.replace('den ', 'd ') return clean(s) fn = clean(first_name) ln = clean_ln(last_name) users = [ u for u in Es.users() if u.first_name and clean(u.first_name) == fn ] # First, simply try the first_name. This is OK if the name is not taken # and there is noone else with that first_name. if fn not in names and len(users) == 0: return fn # Try first_name with a few letters of last_name. for i in xrange(len(ln)): n = fn + ln[:i + 1] if n in names: continue ok = True for u in users: un = clean(u.first_name) + clean_ln(u.last_name) if un.startswith(n): ok = False break if ok: return n # Try <first_name><last_name><i> for i in {2,3,...} i = 1 while True: i += 1 n = fn + ln + str(i) if n not in names: return n
def find_name_for_user(first_name, last_name): """ Given the first and the last name of a user, find a free name """ names = Es.names() def clean(s): return filter(lambda x: x in settings.USERNAME_CHARS, s.lower()) def clean_ln(s): if ',' in s: bits = s.split(',',2) s = bits[1] + ' ' + bits[0] s = s.lower() s = s.replace('van ', 'v ') s = s.replace('de ', 'd ') s = s.replace('der ', 'd ') s = s.replace('den ', 'd ') return clean(s) fn = clean(first_name) ln = clean_ln(last_name) users = [u for u in Es.users() if u.first_name and clean(u.first_name) == fn] # First, simply try the first_name. This is OK if the name is not taken # and there is noone else with that first_name. if fn not in names and len(users) == 0: return fn # Try first_name with a few letters of last_name. for i in xrange(len(ln)): n = fn + ln[:i+1] if n in names: continue ok = True for u in users: un = clean(u.first_name) + clean_ln(u.last_name) if un.startswith(n): ok = False break if ok: return n # Try <first_name><last_name><i> for i in {2,3,...} i = 1 while True: i += 1 n = fn + ln + str(i) if n not in names: return n
def users_underage(request): users = Es.users() users = filter(lambda u: u.is_active, users) users = filter(lambda u: u.is_underage, users) users = sorted(users, key=lambda x: x.dateOfBirth) return render(request, 'leden/entities_underage.html', {'users': users})
def _entity_detail(request, e): related = sorted( e.get_related(), key=lambda x: (Es.DT_MIN - Es.relation_until( x), Es.entity_humanName(x['with']), Es.entity_humanName(x['how']))) rrelated = sorted( e.get_rrelated(), key=lambda x: (Es.DT_MIN - Es.relation_until( x), Es.entity_humanName(x['how']), Es.entity_humanName(x['who']))) for r in chain(related, rrelated): r['may_end'] = Es.user_may_end_relation(request.user, r) r['id'] = r['_id'] r['until_year'] = (None if r['until'] is None or r['until'] >= now() else Es.date_to_year(r['until'])) r['virtual'] = Es.relation_is_virtual(r) tags = [t.as_primary_type() for t in e.get_tags()] # mapping of year => set of members year_sets = {} for r in rrelated: year = r['until_year'] if year is None: year = 'this' if year not in year_sets: year_sets[year] = set() year_sets[year].add(r['who']) year_counts = {} for year in year_sets: year_counts[year] = len(year_sets[year]) ctx = { 'related': related, 'rrelated': rrelated, 'year_counts': year_counts, 'now': now(), 'tags': sorted(tags, key=Es.entity_humanName), 'object': e, 'chiefs': [], 'pipos': [], 'reps': [] } for r in rrelated: if r['how'] and Es.relation_is_active(r): if str(r['how'].name) == '!brand-hoofd': r['hidden'] = True ctx['chiefs'].append(r) if str(r['how'].name) == '!brand-bestuurspipo': r['hidden'] = True ctx['pipos'].append(r) if str(r['how'].name) == '!brand-vertegenwoordiger': r['hidden'] = True ctx['reps'].append(r) # Is request.user allowed to add (r)relations? if ('secretariaat' in request.user.cached_groups_names and (e.is_group or e.is_user)): groups = [g for g in Es.groups() if not g.is_virtual] groups.sort(key=Es.entity_humanName) users = sorted(Es.users(), key=Es.entity_humanName) brands = sorted(Es.brands(), key=Es.entity_humanName) ctx.update({ 'users': users, 'brands': brands, 'groups': groups, 'may_add_related': True, 'may_add_rrelated': True, 'may_tag': True, 'may_untag': True }) ctx['may_upload_smoel'] = e.name and request.user.may_upload_smoel_for(e) if e.is_tag: ctx.update({ 'tag_bearers': sorted(e.as_tag().get_bearers(), key=Es.entity_humanName) }) # Check whether entity has a photo photo_size = e.photo_size if e.photo_size is not None: ctx.update({ 'hasPhoto': True, 'photoWidth': photo_size[0], 'photoHeight': photo_size[1] }) return ctx
# vim: et:sta:bs=2:sw=4: from __future__ import print_function import _import # noqa: F401 import sys from common import args_to_users from django.utils import six from django.utils.six.moves import range import kn.leden.entities as Es users = dict() if len(sys.argv) == 1: _users = Es.users() else: _users = args_to_users(sys.argv[1:]) for m in _users: users[str(m.name)] = set() i = 0 while True: i += 1 g = Es.by_name('leden%s' % i) if g is None: break for m in g.get_members(): if str(m.name) in users: users[str(m.name)].add(i)
def _entity_detail(request, e): def _cmp(x, y): r = Es.relation_cmp_until(y, x) if r: return r r = cmp(unicode(x["with"].humanName), unicode(y["with"].humanName)) if r: return r r = cmp(unicode(x["how"].humanName) if x["how"] else None, unicode(y["how"].humanName) if y["how"] else None) if r: return r return Es.relation_cmp_from(x, y) def _rcmp(x, y): r = Es.relation_cmp_until(y, x) if r: return r r = cmp(unicode(x["how"].humanName) if x["how"] else None, unicode(y["how"].humanName) if y["how"] else None) if r: return r r = cmp(unicode(x["who"].humanName), unicode(y["who"].humanName)) if r: return r return Es.relation_cmp_from(x, y) related = sorted(e.get_related(), cmp=_cmp) rrelated = sorted(e.get_rrelated(), cmp=_rcmp) for r in chain(related, rrelated): r["may_end"] = Es.user_may_end_relation(request.user, r) r["id"] = r["_id"] r["until_year"] = None if r["until"] is None or r["until"] >= now() else Es.date_to_year(r["until"]) r["virtual"] = Es.relation_is_virtual(r) tags = [t.as_primary_type() for t in e.get_tags()] # mapping of year => set of members year_sets = {} for r in rrelated: year = r["until_year"] if year is None: year = "this" if not year in year_sets: year_sets[year] = set() year_sets[year].add(r["who"]) year_counts = {} for year in year_sets: year_counts[year] = len(year_sets[year]) ctx = { "related": related, "rrelated": rrelated, "year_counts": year_counts, "now": now(), "tags": sorted(tags, Es.entity_cmp_humanName), "object": e, "chiefs": [], "pipos": [], "reps": [], } for r in rrelated: if r["how"] and Es.relation_is_active(r): if str(r["how"].name) == "!brand-hoofd": r["hidden"] = True ctx["chiefs"].append(r) if str(r["how"].name) == "!brand-bestuurspipo": r["hidden"] = True ctx["pipos"].append(r) if str(r["how"].name) == "!brand-vertegenwoordiger": r["hidden"] = True ctx["reps"].append(r) # Is request.user allowed to add (r)relations? if "secretariaat" in request.user.cached_groups_names and (e.is_group or e.is_user): groups = [g for g in Es.groups() if not g.is_virtual] groups.sort(cmp=lambda x, y: cmp(unicode(x.humanName), unicode(y.humanName))) users = sorted(Es.users(), cmp=Es.entity_cmp_humanName) brands = sorted(Es.brands(), cmp=Es.entity_cmp_humanName) ctx.update( { "users": users, "brands": brands, "groups": groups, "may_add_related": True, "may_add_rrelated": True, "may_tag": True, "may_untag": True, } ) ctx["may_upload_smoel"] = e.name and request.user.may_upload_smoel_for(e) if e.is_tag: ctx.update({"tag_bearers": sorted(e.as_tag().get_bearers(), cmp=Es.entity_cmp_humanName)}) # Check whether entity has a photo photos_path = path.join(settings.SMOELEN_PHOTOS_PATH, str(e.name)) if e.name else None if photos_path and default_storage.exists(photos_path + ".jpg"): img = Image.open(default_storage.open(photos_path + ".jpg")) width, height = img.size if default_storage.exists(photos_path + ".orig"): # smoel was created using newer strategy. Shrink until it fits the # requirements. width, height = resize_proportional( img.size[0], img.size[1], settings.SMOELEN_WIDTH, settings.SMOELEN_HEIGHT ) elif width > settings.SMOELEN_WIDTH: # smoel was created as high-resolution image, probably 600px wide width /= 2 height /= 2 else: # smoel was created as normal image, probably 300px wide pass ctx.update({"hasPhoto": True, "photoWidth": width, "photoHeight": height}) return ctx
# vim: et:sta:bs=2:sw=4: import _import import sys from common import * import kn.leden.entities as Es users = dict() if len(sys.argv) == 1: _users = Es.users() else: _users = args_to_users(sys.argv[1:]) for m in _users: users[str(m.name)] = set() i = 0 while True: i += 1 g = Es.by_name('leden%s' % i) if g is None: break for m in g.get_members(): if str(m.name) in users: users[str(m.name)].add(i) nyears = i - 1 N = 0 for m, ys in users.iteritems(): N += 1 if N % 20 == 0:
def _entity_detail(request, e): def _cmp(x,y): r = Es.relation_cmp_until(y,x) if r: return r r = cmp(unicode(x['with'].humanName), unicode(y['with'].humanName)) if r: return r r = cmp(unicode(x['how'].humanName) if x['how'] else None, unicode(y['how'].humanName) if y['how'] else None) if r: return r return Es.relation_cmp_from(x,y) def _rcmp(x,y): r = Es.relation_cmp_until(y,x) if r: return r r = cmp(unicode(x['how'].humanName) if x['how'] else None, unicode(y['how'].humanName) if y['how'] else None) if r: return r r = cmp(unicode(x['who'].humanName), unicode(y['who'].humanName)) if r: return r return Es.relation_cmp_from(x,y) related = sorted(e.get_related(), cmp=_cmp) rrelated = sorted(e.get_rrelated(), cmp=_rcmp) for r in chain(related, rrelated): r['may_end'] = Es.user_may_end_relation(request.user, r) r['id'] = r['_id'] r['until_year'] = (None if r['until'] is None else Es.date_to_year(r['until'])) r['virtual'] = Es.relation_is_virtual(r) tags = [t.as_primary_type() for t in e.get_tags()] # mapping of year => set of members year_sets = {} for r in rrelated: year = r['until_year'] if year is None: year = 'this' if not year in year_sets: year_sets[year] = set() year_sets[year].add(r['who']) year_counts = {} for year in year_sets: year_counts[year] = len(year_sets[year]) ctx = {'related': related, 'rrelated': rrelated, 'year_counts': year_counts, 'now': now(), 'tags': sorted(tags, Es.entity_cmp_humanName), 'object': e, 'chiefs': [], 'pipos': [] } for r in rrelated: if r['how'] and Es.relation_is_active(r): if str(r['how'].name) == '!brand-hoofd': r['hidden'] = True ctx['chiefs'].append(r) if str(r['how'].name) == '!brand-bestuurspipo': r['hidden'] = True ctx['pipos'].append(r) # Is request.user allowed to add (r)relations? if ('secretariaat' in request.user.cached_groups_names and (e.is_group or e.is_user)): groups = [g for g in Es.groups() if not g.is_virtual] groups.sort(cmp=lambda x,y: cmp(unicode(x.humanName), unicode(y.humanName))) users = sorted(Es.users(), cmp=Es.entity_cmp_humanName) brands = sorted(Es.brands(), cmp=Es.entity_cmp_humanName) ctx.update({'users': users, 'brands': brands, 'groups': groups, 'may_add_related': True, 'may_add_rrelated': True}) if e.is_tag: ctx.update({'tag_bearers': sorted(e.as_tag().get_bearers(), cmp=Es.entity_cmp_humanName)}) return ctx
def fotos(request, path=''): path = unquote(path) if any(k in request.GET for k in ['album', 'search_album', 'search_tag']): # redirect old URL path = request.GET.get('album', '') q = None if request.GET.get('search_album'): q = 'album:' + request.GET.get('search_album') if request.GET.get('search_tag'): q = 'tag:' + request.GET.get('search_tag') url = reverse('fotos', kwargs={'path': path}) if q is not None: qs = QueryDict('', mutable=True) qs['q'] = q url += '?' + qs.urlencode() return redirect(url, permanent=True) album = fEs.by_path(path) if album is None: bits = path.rsplit('/', 1) if len(bits) == 2: path = bits[0] name = bits[1].replace('+', ' ') entity = fEs.by_path_and_name(path, name) if entity is not None: # Zen Photo used + signs in the filename part of the URL. url = reverse('fotos', kwargs={'path': path}) \ + '#' + filepath_to_uri(name) return redirect(url, permanent=True) raise Http404 if album._type != 'album': # This is a photo, not an album. # Backwards compatibility, probably to Zen Photo. url = reverse('fotos', kwargs={'path': album.path}) \ + '#' + filepath_to_uri(album.name) return redirect(url, permanent=True) user = request.user if request.user.is_authenticated() else None if not album.may_view(user) and user is None: # user is not logged in return redirect_to_login(request.get_full_path()) if not album.may_view(user): # user is logged in, but may not view the album title = album.title if not title: title = album.name # respond with a nice error message response = render_to_response( 'fotos/fotos.html', {'fotos': {'parents': album_parents_json(album)}, 'error': 'permission-denied'}, context_instance=RequestContext(request) ) response.status_code = 403 return response if 'download' in request.GET: if album.is_root: # Downloading ALL photos would be way too much raise PermissionDenied download = ZipSeeker() add_download_files(download, album, album.full_path, user) response = StreamingHttpResponse(download.blocks(), content_type='application/zip') response['Content-Length'] = download.size() response['Last-Modified'] = http_date(download.lastModified()) # TODO: human-readable download name? response['Content-Disposition'] = 'attachment; filename=' + \ album.name + '.zip' return response people = None if fEs.is_admin(user): # Get all members (now or in the past), and sort them first # by whether they are active (active members first) and # then by their name. humanNames = {} active = [] inactive = [] for u in Es.users(): humanNames[str(u.name)] = six.text_type(u.humanName) if u.is_active: active.append(str(u.name)) else: inactive.append(str(u.name)) active.sort() inactive.sort() people = [] for name in active + inactive: people.append((name, humanNames[name])) fotos = album_json(album, user) return render_to_response('fotos/fotos.html', {'fotos': fotos, 'fotos_admin': fEs.is_admin(user), 'people': people}, context_instance=RequestContext(request))
def update_db(giedo): dt_now = now() # Load tags # TODO cache this tags = Es.ids_by_names(('!year-group', '!year-overrides', '!virtual-group', '!sofa-brand')) year_overrides = {} for t in Es.bearers_by_tag_id(tags['!year-overrides'], _as=Es.Tag): year_overrides[t._id] = (t._data['year-override']['type'], t._data['year-override']['year']) # Load _id -> name lut. id2name = Es.names_by_ids() # Load groups and brands groups = Es.of_type_by_name('group') groups_set = frozenset(six.itervalues(groups)) # Find groups that have a virtual group for each year year_groups = [g for g in groups_set if tags['!year-group'] in g.tag_ids] # Find relations on those groups and add the years for which those # relations hold. def add_years_to_relations(rels): years_of_year_overrides = [yo[1] for yo in six.itervalues(year_overrides)] until_years = [Es.date_to_year(r['until']) for r in rels if r['until'] != DT_MAX] max_until = max( max(until_years) if until_years else 0, max(years_of_year_overrides) if years_of_year_overrides else 0, Es.date_to_year(dt_now) ) from_years = [Es.date_to_year(r['from']) for r in rels if r['from'] != DT_MIN] min_from = min(min(from_years) if from_years else Es.date_to_year(dt_now), Es.date_to_year(dt_now)) for rel in rels: s = (min_from if rel['from'] == DT_MIN else Es.date_to_year(rel['from'])) t = (max_until if rel['until'] == DT_MAX else Es.date_to_year(rel['until'])) years = set(range(s, t + 1)) for tid in rel.get('tags', ()): if tid not in year_overrides: continue tp, yr = year_overrides[tid] if tp: years.add(yr) else: if yr not in years: logging.warning('bogus year-override -{} on {}'.format( yr, rel['_id'])) continue years.remove(yr) rel['years'] = years year_group_mrels = tuple(Es.query_relations(_with=year_groups)) # Check whether all year groups are created for g in year_groups: mrels = [rel for rel in year_group_mrels if rel['with'] == g._id] add_years_to_relations(mrels) years = set() for rel in mrels: years.update(rel['years']) for year in years: n = str(g.name) + str(year) if n not in groups: logging.info("Creating yeargroup %s" % n) _create_yeargroup(g, year, n, tags, groups, id2name) # Find all virtual groups virtual_groups = [g for g in groups_set if tags['!virtual-group'] in g.tag_ids] sofa_vgroups = [] yeargroup_vgroups = [] for vg in virtual_groups: if vg._data['virtual']['type'] == 'sofa': sofa_vgroups.append(vg) elif vg._data['virtual']['type'] == 'year-group': yeargroup_vgroups.append(vg) else: logging.warn("Unknown vgroup type: %s" % vg._data['virtua']['type']) # Find all relations with the sofa virtual groups def relkey(rel): return (rel['who'], rel['how'], rel['with'], rel['from'], rel['until']) vgroup_rlut = dict() for rel in Es.query_relations(_with=virtual_groups): vgroup_rlut[relkey(rel)] = rel['_id'] # create look up table of existing sofas sofa_queries = [] sofa_lut = dict() for svg in sofa_vgroups: w = dict(svg._data['virtual']) sofa_queries.append({'how': w['how'], 'with': w['with']}) k = (w['how'], w['with']) if k not in sofa_lut: sofa_lut[k] = [] sofa_lut[k].append(svg) # Check whether all year-group relations are in place # If there are two relations between an entity and a group in the # same year, we do not want this relation to be handled twice. # Thus we keep a seperate look-up-table to prevent this. year_vgroup_rel_ok = set() for mrel in year_group_mrels: g = groups[id2name[mrel['with']]] for year in mrel['years']: yg = groups[str(g.name) + str(year)] rrel = {'who': mrel['who'], 'with': yg._id, 'how': mrel['how'], 'from': DT_MIN, 'until': DT_MAX} if (not relkey(rrel) in vgroup_rlut and relkey(rrel) not in year_vgroup_rel_ok): logging.info("vgroup: adding %s -> %s (%s)" % ( id2name[mrel['who']], yg.name, id2name.get(mrel['how']))) Es.rcol.insert(rrel) elif relkey(rrel) in vgroup_rlut: del vgroup_rlut[relkey(rrel)] year_vgroup_rel_ok.add(relkey(rrel)) # Check whether all sofas are created sofa_brands = {} for b in Es.brands(): if tags['!sofa-brand'] not in b._data['tags']: continue sofa_brands[b._id] = b for rel in Es.query_relations(how=tuple(sofa_brands.values())): if (rel['how'], rel['with']) in sofa_lut: continue if not id2name[rel['with']]: continue g = groups[id2name[rel['with']]] nm = str(g.name) + '-' + sofa_brands[rel['how']].sofa_suffix logging.info("creating sofa %s" % nm) n = {'types': ['group', 'tag'], 'names': [nm], 'tags': [tags['!virtual-group']], 'virtual': { 'type': 'sofa', 'with': rel['with'], 'how': rel['how']}, 'humanNames': [{ 'name': nm, 'human': six.text_type(g.humanName) + ' ' + six.text_type(sofa_brands[rel['how']].humanName)}]} n['_id'] = Es.ecol.insert(n) groups[nm] = Es.Group(n) id2name[n['_id']] = nm sofa_vgroups.append(g) sofa_lut[rel['how'], rel['with']] = [groups[nm]] sofa_queries.append({'how': rel['how'], 'with': rel['with']}) # Find all relations for the sofa virtual groups and check whether # the appropriate relations to the sofas are generated for rel in Es.disj_query_relations(sofa_queries): for svg in sofa_lut[(rel['how'], rel['with'])]: rrel = {'how': None, 'from': rel['from'], 'until': rel['until'], 'who': rel['who'], 'with': svg._id} if not relkey(rrel) in vgroup_rlut: logging.info("sofa: adding %s to %s" % ( id2name[rrel['who']], str(svg.name))) Es.rcol.insert(rrel) else: del vgroup_rlut[relkey(rrel)] # Check which relations to vgroups are unaccounted for and thus are to # be removed. for relkey in vgroup_rlut: logging.info("removing superfluous %s -> %s (%s)" % ( id2name[relkey[0]], id2name.get(relkey[2]), id2name.get(relkey[1]))) Es.remove_relation(relkey[0], relkey[2], relkey[1], relkey[3], relkey[4]) # Set is_active on Users if and only if they are not in the `leden' group. # TODO We might optimize this by including it in a more generic process active_users = [rel['who'] for rel in Es.by_name('leden').get_rrelated( None, dt_now, dt_now, False, False, False)] for u in Es.users(): is_active = u._id in active_users if u.is_active == is_active: continue u._data['is_active'] = is_active u.save() logging.info( "%s user %s", ("activated" if is_active else "deactivated"), str(u.name) )
def fotos(request, path=''): path = unquote(path) if any(k in request.GET for k in ['album', 'search_album', 'search_tag']): # redirect old URL path = request.GET.get('album', '') q = None if request.GET.get('search_album'): q = 'album:' + request.GET.get('search_album') if request.GET.get('search_tag'): q = 'tag:' + request.GET.get('search_tag') url = reverse('fotos', kwargs={'path': path}) if q is not None: qs = QueryDict('', mutable=True) qs['q'] = q url += '?' + qs.urlencode() return redirect(url, permanent=True) album = fEs.by_path(path) if album is None: bits = path.rsplit('/', 1) if len(bits) == 2: path = bits[0] name = bits[1].replace('+', ' ') entity = fEs.by_path_and_name(path, name) if entity is not None: # Zen Photo used + signs in the filename part of the URL. url = reverse('fotos', kwargs={'path': path}) \ + '#' + filepath_to_uri(name) return redirect(url, permanent=True) raise Http404 if album._type != 'album': # This is a photo, not an album. # Backwards compatibility, probably to Zen Photo. url = reverse('fotos', kwargs={'path': album.path}) \ + '#' + filepath_to_uri(album.name) return redirect(url, permanent=True) user = request.user if request.user.is_authenticated() else None if not album.may_view(user) and user is None: # user is not logged in return redirect_to_login(request.get_full_path()) if not album.may_view(user): # user is logged in, but may not view the album title = album.title if not title: title = album.name # respond with a nice error message response = render( request, 'fotos/fotos.html', {'fotos': {'parents': album_parents_json(album)}, 'error': 'permission-denied'}, ) response.status_code = 403 return response if 'download' in request.GET: if album.is_root: # Downloading ALL photos would be way too much raise PermissionDenied download = ZipSeeker() add_download_files(download, album, album.full_path, user) response = StreamingHttpResponse(download.blocks(), content_type='application/zip') response['Content-Length'] = download.size() response['Last-Modified'] = http_date(download.lastModified()) # TODO: human-readable download name? response['Content-Disposition'] = 'attachment; filename=' + \ album.name + '.zip' return response people = None if fEs.is_admin(user): # Get all members (now or in the past), and sort them first # by whether they are active (active members first) and # then by their name. humanNames = {} active = [] inactive = [] for u in Es.users(): humanNames[str(u.name)] = six.text_type(u.humanName) if u.is_active: active.append(str(u.name)) else: inactive.append(str(u.name)) active.sort() inactive.sort() people = [] for name in active + inactive: people.append((name, humanNames[name])) fotos = album_json(album, user) return render(request, 'fotos/fotos.html', {'fotos': fotos, 'fotos_admin': fEs.is_admin(user), 'people': people})
def _entity_detail(request, e): related = sorted(e.get_related(), key=lambda x: (Es.DT_MIN - Es.relation_until(x), Es.entity_humanName(x['with']), Es.entity_humanName(x['how']))) rrelated = sorted(e.get_rrelated(), key=lambda x: (Es.DT_MIN - Es.relation_until(x), Es.entity_humanName(x['how']), Es.entity_humanName(x['who']))) for r in chain(related, rrelated): r['may_end'] = Es.user_may_end_relation(request.user, r) r['id'] = r['_id'] r['until_year'] = (None if r['until'] is None or r['until'] >= now() else Es.date_to_year(r['until'])) r['virtual'] = Es.relation_is_virtual(r) tags = [t.as_primary_type() for t in e.get_tags()] # mapping of year => set of members year_sets = {} for r in rrelated: year = r['until_year'] if year is None: year = 'this' if year not in year_sets: year_sets[year] = set() year_sets[year].add(r['who']) year_counts = {} for year in year_sets: year_counts[year] = len(year_sets[year]) ctx = {'related': related, 'rrelated': rrelated, 'year_counts': year_counts, 'now': now(), 'tags': sorted(tags, key=Es.entity_humanName), 'object': e, 'chiefs': [], 'pipos': [], 'reps': []} for r in rrelated: if r['how'] and Es.relation_is_active(r): if str(r['how'].name) == '!brand-hoofd': r['hidden'] = True ctx['chiefs'].append(r) if str(r['how'].name) == '!brand-bestuurspipo': r['hidden'] = True ctx['pipos'].append(r) if str(r['how'].name) == '!brand-vertegenwoordiger': r['hidden'] = True ctx['reps'].append(r) # Is request.user allowed to add (r)relations? if ('secretariaat' in request.user.cached_groups_names and (e.is_group or e.is_user)): groups = [g for g in Es.groups() if not g.is_virtual] groups.sort(key=Es.entity_humanName) users = sorted(Es.users(), key=Es.entity_humanName) brands = sorted(Es.brands(), key=Es.entity_humanName) ctx.update({'users': users, 'brands': brands, 'groups': groups, 'may_add_related': True, 'may_add_rrelated': True, 'may_tag': True, 'may_untag': True}) ctx['may_upload_smoel'] = e.name and request.user.may_upload_smoel_for(e) if e.is_tag: ctx.update({'tag_bearers': sorted(e.as_tag().get_bearers(), key=Es.entity_humanName)}) # Check whether entity has a photo photos_path = (path.join(settings.SMOELEN_PHOTOS_PATH, str(e.name)) if e.name else None) if photos_path and default_storage.exists(photos_path + '.jpg'): img = PIL.Image.open(default_storage.open(photos_path + '.jpg')) width, height = img.size if default_storage.exists(photos_path + '.orig'): # smoel was created using newer strategy. Shrink until it fits the # requirements. width, height = resize_proportional(img.size[0], img.size[1], settings.SMOELEN_WIDTH, settings.SMOELEN_HEIGHT) elif width > settings.SMOELEN_WIDTH: # smoel was created as high-resolution image, probably 600px wide width /= 2 height /= 2 else: # smoel was created as normal image, probably 300px wide pass ctx.update({ 'hasPhoto': True, 'photoWidth': width, 'photoHeight': height}) return ctx
def update_db(giedo): dt_now = now() # Load tags # TODO cache this tags = Es.ids_by_names( ('!year-group', '!year-overrides', '!virtual-group', '!sofa-brand')) year_overrides = {} for t in Es.bearers_by_tag_id(tags['!year-overrides'], _as=Es.Tag): year_overrides[t._id] = (t._data['year-override']['type'], t._data['year-override']['year']) # Load _id -> name lut. id2name = Es.names_by_ids() # Load groups and brands groups = Es.of_type_by_name('group') groups_set = frozenset(six.itervalues(groups)) # Find groups that have a virtual group for each year year_groups = [g for g in groups_set if tags['!year-group'] in g.tag_ids] # Find relations on those groups and add the years for which those # relations hold. def add_years_to_relations(rels): years_of_year_overrides = [ yo[1] for yo in six.itervalues(year_overrides) ] until_years = [ Es.date_to_year(r['until']) for r in rels if r['until'] != DT_MAX ] max_until = max( max(until_years) if until_years else 0, max(years_of_year_overrides) if years_of_year_overrides else 0, Es.date_to_year(dt_now)) from_years = [ Es.date_to_year(r['from']) for r in rels if r['from'] != DT_MIN ] min_from = min( min(from_years) if from_years else Es.date_to_year(dt_now), Es.date_to_year(dt_now)) for rel in rels: s = (min_from if rel['from'] == DT_MIN else Es.date_to_year(rel['from'])) t = (max_until if rel['until'] == DT_MAX else Es.date_to_year(rel['until'])) years = set(range(s, t + 1)) for tid in rel.get('tags', ()): if tid not in year_overrides: continue tp, yr = year_overrides[tid] if tp: years.add(yr) else: if yr not in years: logging.warning('bogus year-override -{} on {}'.format( yr, rel['_id'])) continue years.remove(yr) rel['years'] = years year_group_mrels = tuple(Es.query_relations(_with=year_groups)) # Check whether all year groups are created for g in year_groups: mrels = [rel for rel in year_group_mrels if rel['with'] == g._id] add_years_to_relations(mrels) years = set() for rel in mrels: years.update(rel['years']) for year in years: n = str(g.name) + str(year) if n not in groups: logging.info("Creating yeargroup %s" % n) _create_yeargroup(g, year, n, tags, groups, id2name) # Find all virtual groups virtual_groups = [ g for g in groups_set if tags['!virtual-group'] in g.tag_ids ] sofa_vgroups = [] yeargroup_vgroups = [] for vg in virtual_groups: if vg._data['virtual']['type'] == 'sofa': sofa_vgroups.append(vg) elif vg._data['virtual']['type'] == 'year-group': yeargroup_vgroups.append(vg) else: logging.warn("Unknown vgroup type: %s" % vg._data['virtua']['type']) # Find all relations with the sofa virtual groups def relkey(rel): return (rel['who'], rel['how'], rel['with'], rel['from'], rel['until']) vgroup_rlut = dict() for rel in Es.query_relations(_with=virtual_groups): vgroup_rlut[relkey(rel)] = rel['_id'] # create look up table of existing sofas sofa_queries = [] sofa_lut = dict() for svg in sofa_vgroups: w = dict(svg._data['virtual']) sofa_queries.append({'how': w['how'], 'with': w['with']}) k = (w['how'], w['with']) if k not in sofa_lut: sofa_lut[k] = [] sofa_lut[k].append(svg) # Check whether all year-group relations are in place # If there are two relations between an entity and a group in the # same year, we do not want this relation to be handled twice. # Thus we keep a seperate look-up-table to prevent this. year_vgroup_rel_ok = set() for mrel in year_group_mrels: g = groups[id2name[mrel['with']]] for year in mrel['years']: yg = groups[str(g.name) + str(year)] rrel = { 'who': mrel['who'], 'with': yg._id, 'how': mrel['how'], 'from': DT_MIN, 'until': DT_MAX } if (not relkey(rrel) in vgroup_rlut and relkey(rrel) not in year_vgroup_rel_ok): logging.info( "vgroup: adding %s -> %s (%s)" % (id2name[mrel['who']], yg.name, id2name.get(mrel['how']))) Es.rcol.insert(rrel) elif relkey(rrel) in vgroup_rlut: del vgroup_rlut[relkey(rrel)] year_vgroup_rel_ok.add(relkey(rrel)) # Check whether all sofas are created sofa_brands = {} for b in Es.brands(): if tags['!sofa-brand'] not in b._data['tags']: continue sofa_brands[b._id] = b for rel in Es.query_relations(how=tuple(sofa_brands.values())): if (rel['how'], rel['with']) in sofa_lut: continue if not id2name[rel['with']]: continue g = groups[id2name[rel['with']]] nm = str(g.name) + '-' + sofa_brands[rel['how']].sofa_suffix logging.info("creating sofa %s" % nm) n = { 'types': ['group', 'tag'], 'names': [nm], 'tags': [tags['!virtual-group']], 'virtual': { 'type': 'sofa', 'with': rel['with'], 'how': rel['how'] }, 'humanNames': [{ 'name': nm, 'human': six.text_type(g.humanName) + ' ' + six.text_type(sofa_brands[rel['how']].humanName) }] } n['_id'] = Es.ecol.insert(n) groups[nm] = Es.Group(n) id2name[n['_id']] = nm sofa_vgroups.append(g) sofa_lut[rel['how'], rel['with']] = [groups[nm]] sofa_queries.append({'how': rel['how'], 'with': rel['with']}) # Find all relations for the sofa virtual groups and check whether # the appropriate relations to the sofas are generated for rel in Es.disj_query_relations(sofa_queries): for svg in sofa_lut[(rel['how'], rel['with'])]: rrel = { 'how': None, 'from': rel['from'], 'until': rel['until'], 'who': rel['who'], 'with': svg._id } if not relkey(rrel) in vgroup_rlut: logging.info("sofa: adding %s to %s" % (id2name[rrel['who']], str(svg.name))) Es.rcol.insert(rrel) else: del vgroup_rlut[relkey(rrel)] # Check which relations to vgroups are unaccounted for and thus are to # be removed. for relkey in vgroup_rlut: logging.info("removing superfluous %s -> %s (%s)" % (id2name[relkey[0]], id2name.get( relkey[2]), id2name.get(relkey[1]))) Es.remove_relation(relkey[0], relkey[2], relkey[1], relkey[3], relkey[4]) # Set is_active on Users if and only if they are not in the `leden' group. # TODO We might optimize this by including it in a more generic process active_users = [ rel['who'] for rel in Es.by_name('leden').get_rrelated( None, dt_now, dt_now, False, False, False) ] for u in Es.users(): is_active = u._id in active_users if u.is_active == is_active: continue u._data['is_active'] = is_active u.save() logging.info("%s user %s", ("activated" if is_active else "deactivated"), str(u.name))
def fotos(request, path=''): path = unquote(path) if any(k in request.GET for k in ['album', 'search_album', 'search_tag']): # redirect old URL path = request.GET.get('album', '') q = None if request.GET.get('search_album'): q = 'album:' + request.GET.get('search_album') if request.GET.get('search_tag'): q = 'tag:' + request.GET.get('search_tag') url = reverse('fotos', kwargs={'path':path}) if q is not None: qs = QueryDict('', mutable=True) qs['q'] = q url += '?' + qs.urlencode() return redirect(url, permanent=True) album = fEs.by_path(path) if album is None: bits = path.rsplit('/', 1) if len(bits) == 2: path = bits[0] name = bits[1].replace('+', ' ') entity = fEs.by_path_and_name(path, name) if entity is not None: # Zen Photo used + signs in the filename part of the URL. url = reverse('fotos', kwargs={'path':path}) \ + '#'+filepath_to_uri(name) return redirect(url, permanent=True) raise Http404 if album._type != 'album': # This is a photo, not an album. # Backwards compatibility, probably to Zen Photo. url = reverse('fotos', kwargs={'path':album.path}) \ + '#'+filepath_to_uri(album.name) return redirect(url, permanent=True) user = request.user if request.user.is_authenticated() else None if not album.may_view(user) and user is None: # user is not logged in return redirect_to_login(request.get_full_path()) if not album.may_view(user): # user is logged in, but may not view the album title = album.title if not title: title = album.name # respond with a nice error message response = render_to_response('fotos/fotos.html', {'fotos': {'parents': album_parents_json(album)}, 'error': 'permission-denied'}, context_instance=RequestContext(request)) response.status_code = 403 return response people = None if fEs.is_admin(user): # Get all members (now or in the past), and sort them first by whether they # are active (active members first) and then by their name. humanNames = {} active = [] inactive = [] for u in Es.users(): humanNames[str(u.name)] = unicode(u.humanName) if u.is_active: active.append(str(u.name)) else: inactive.append(str(u.name)) active.sort() inactive.sort() people = [] for name in active+inactive: people.append((name, humanNames[name])) fotos = album_json(album, user) return render_to_response('fotos/fotos.html', {'fotos': fotos, 'fotos_admin': fEs.is_admin(user), 'people': people}, context_instance=RequestContext(request))
def _entity_detail(request, e): related = sorted(e.get_related(), key=lambda x: (Es.DT_MIN - Es.relation_until(x), Es.entity_humanName(x['with']), Es.entity_humanName(x['how']))) rrelated = sorted(e.get_rrelated(), key=lambda x: (Es.DT_MIN - Es.relation_until(x), Es.entity_humanName(x['how']), Es.entity_humanName(x['who']))) for r in chain(related, rrelated): r['may_end'] = Es.user_may_end_relation(request.user, r) r['id'] = r['_id'] r['until_year'] = (None if r['until'] is None or r['until'] >= now() else Es.date_to_year(r['until'])) r['virtual'] = Es.relation_is_virtual(r) tags = [t.as_primary_type() for t in e.get_tags()] # mapping of year => set of members year_sets = {} for r in rrelated: year = r['until_year'] if year is None: year = 'this' if year not in year_sets: year_sets[year] = set() year_sets[year].add(r['who']) year_counts = {} for year in year_sets: year_counts[year] = len(year_sets[year]) ctx = {'related': related, 'rrelated': rrelated, 'year_counts': year_counts, 'now': now(), 'tags': sorted(tags, key=Es.entity_humanName), 'object': e, 'chiefs': [], 'pipos': [], 'reps': []} for r in rrelated: if r['how'] and Es.relation_is_active(r): if str(r['how'].name) == '!brand-hoofd': r['hidden'] = True ctx['chiefs'].append(r) if str(r['how'].name) == '!brand-bestuurspipo': r['hidden'] = True ctx['pipos'].append(r) if str(r['how'].name) == '!brand-vertegenwoordiger': r['hidden'] = True ctx['reps'].append(r) # Is request.user allowed to add (r)relations? if ('secretariaat' in request.user.cached_groups_names and (e.is_group or e.is_user)): groups = [g for g in Es.groups() if not g.is_virtual] groups.sort(key=Es.entity_humanName) users = sorted(Es.users(), key=Es.entity_humanName) brands = sorted(Es.brands(), key=Es.entity_humanName) ctx.update({'users': users, 'brands': brands, 'groups': groups, 'may_add_related': True, 'may_add_rrelated': True, 'may_tag': True, 'may_untag': True}) ctx['may_upload_smoel'] = e.name and request.user.may_upload_smoel_for(e) if e.is_tag: ctx.update({'tag_bearers': sorted(e.as_tag().get_bearers(), key=Es.entity_humanName)}) # Check whether entity has a photo photo_size = e.photo_size if e.photo_size is not None: ctx.update({ 'hasPhoto': True, 'photoWidth': photo_size[0], 'photoHeight': photo_size[1]}) return ctx