def delete_extract(request): user_id = request.authenticated_userid discussion_id = int(request.matchdict['discussion_id']) if not user_id: # Straight from annotator token = request.headers.get('X-Annotator-Auth-Token') if token: token = decode_token(token, request.registry.settings['session.secret']) if token: user_id = token['userId'] user_id = user_id or Everyone extract_id = request.matchdict['id'] extract = Extract.get_instance(extract_id) if not (user_has_permission(discussion_id, user_id, P_EDIT_EXTRACT) or (user_has_permission(discussion_id, user_id, P_EDIT_MY_EXTRACT) and user_id == extract.owner_id)): raise HTTPForbidden() if not extract: return HTTPNoContent() # TODO: Tombstonable extracts??? extract.delete() return HTTPNoContent()
def delete_extract(request): user_id = authenticated_userid(request) discussion_id = int(request.matchdict['discussion_id']) if not user_id: # Straight from annotator token = request.headers.get('X-Annotator-Auth-Token') if token: token = decode_token( token, request.registry.settings['session.secret']) if token: user_id = token['userId'] user_id = user_id or Everyone extract_id = request.matchdict['id'] extract = Extract.get_instance(extract_id) if not (user_has_permission(discussion_id, user_id, P_EDIT_EXTRACT) or (user_has_permission(discussion_id, user_id, P_EDIT_MY_EXTRACT) and user_id == extract.owner_id)): raise HTTPForbidden() if not extract: return HTTPNoContent() with transaction.manager: # TODO: Tombstonable extracts??? Extract.default_db.delete(extract) request.response.status = HTTPNoContent.code return HTTPNoContent()
def put_extract(request): """ Updating an Extract """ extract_id = request.matchdict['id'] user_id = authenticated_userid(request) discussion = request.context if not user_id: # Straight from annotator token = request.headers.get('X-Annotator-Auth-Token') if token: token = decode_token(token, request.registry.settings['session.secret']) if token: user_id = token['userId'] user_id = user_id or Everyone updated_extract_data = json.loads(request.body) extract = Extract.get_instance(extract_id) if not extract: raise HTTPNotFound("Extract with id '%s' not found." % extract_id) if not (user_has_permission(discussion.id, user_id, P_EDIT_EXTRACT) or (user_has_permission(discussion.id, user_id, P_EDIT_MY_EXTRACT) and user_id == extract.owner_id)): raise HTTPForbidden() extract.owner_id = user_id or AgentProfile.get_database_id( extract.owner_id) extract.order = updated_extract_data.get('order', extract.order) extract.important = updated_extract_data.get('important', extract.important) idea_id = updated_extract_data.get('idIdea', None) if idea_id: idea = Idea.get_instance(idea_id) if (idea.discussion != extract.discussion): raise HTTPBadRequest( "Extract from discussion %s cannot be associated with an idea from a different discussion." % extract.get_discussion_id()) extract.idea = idea else: extract.idea = None Extract.default_db.add(extract) #TODO: Merge ranges. Sigh. return {'ok': True}
def discussion_list_view(request): request.session.pop('discussion') user_id = authenticated_userid(request) or Everyone user = None if user_id != Everyone: user = User.get(user_id) roles = get_roles(user_id) context = get_default_context(request) context['discussions'] = [] # Show even anonymous users every discussion one has access to if # authenticated, so they can login and read them discussions = discussions_with_access(Authenticated if user_id == Everyone else user_id) for discussion in discussions: discussionFrontendUrls = FrontendUrls(discussion) discussion_context = { 'topic': discussion.topic, 'slug': discussion.slug, 'url': discussionFrontendUrls.get_discussion_url() } if user_has_permission(discussion.id, user_id, P_ADMIN_DISC): discussion_context[ 'admin_url'] = discussionFrontendUrls.get_discussion_edition_url( ) discussion_context['permissions_url'] = request.route_url( 'discussion_permissions', discussion_id=discussion.id) context['discussions'].append(discussion_context) if R_SYSADMIN in roles: context['discussions_admin_url'] = request.route_url( 'discussion_admin') context['permissions_admin_url'] = request.route_url( 'general_permissions') context['user'] = user return context
def discussion_list_view(request): user_id = authenticated_userid(request) or Everyone user = None if user_id != Everyone: user = User.get(user_id) roles = get_roles(user_id) context = get_default_context(request) context['discussions'] = [] #Show even anonymous users every discussion one has access to if #authenticated, so they can login and read them discussions = discussions_with_access(Authenticated if user_id == Everyone else user_id) for discussion in discussions: discussionFrontendUrls = FrontendUrls(discussion) discussion_context = { 'topic': discussion.topic, 'slug': discussion.slug, 'url': discussionFrontendUrls.get_discussion_url() } if user_has_permission(discussion.id, user_id, P_ADMIN_DISC): discussion_context['admin_url'] = discussionFrontendUrls.get_discussion_edition_url() discussion_context['permissions_url'] = request.route_url( 'discussion_permissions', discussion_id=discussion.id) context['discussions'].append(discussion_context) if R_SYSADMIN in roles: context['discussions_admin_url'] = request.route_url('discussion_admin') context['permissions_admin_url'] = request.route_url('general_permissions') context['user'] = user return context
def do_search_extracts(request): uri = request.GET.get('uri', None) if not uri: raise HTTPClientError("Please specify a URI") view_def = request.GET.get('view') or 'default' discussion = request.context user_id = authenticated_userid(request) if not user_id: # Straight from annotator token = request.headers.get('X-Annotator-Auth-Token') if token: token = decode_token(token, request.registry.settings['session.secret']) if token: user_id = token['userId'] user_id = user_id or Everyone if not user_has_permission(discussion.id, user_id, P_READ): raise HTTPForbidden() permissions = [P_READ] if not uri: raise HTTPBadRequest("Please specify a search uri") content = Webpage.get_by(url=uri) if content: extracts = Extract.default_db.query(Extract).filter_by( content=content).all() rows = [ extract.generic_json(view_def, user_id, permissions) for extract in extracts ] return {"total": len(extracts), "rows": rows} return {"total": 0, "rows": []}
def put_extract(request): """ Updating an Extract """ extract_id = request.matchdict['id'] user_id = authenticated_userid(request) discussion_id = int(request.matchdict['discussion_id']) if not user_id: # Straight from annotator token = request.headers.get('X-Annotator-Auth-Token') if token: token = decode_token( token, request.registry.settings['session.secret']) if token: user_id = token['userId'] if not user_id: user_id = Everyone updated_extract_data = json.loads(request.body) extract = Extract.get_instance(extract_id) if not extract: raise HTTPNotFound("Extract with id '%s' not found." % extract_id) if not (user_has_permission(discussion_id, user_id, P_EDIT_EXTRACT) or (user_has_permission(discussion_id, user_id, P_EDIT_MY_EXTRACT) and user_id == extract.owner_id)): return HTTPForbidden() extract.owner_id = user_id or get_database_id("User", extract.owner_id) extract.order = updated_extract_data.get('order', extract.order) extract.important = updated_extract_data.get('important', extract.important) idea_id = updated_extract_data.get('idIdea', None) if idea_id: idea = Idea.get_instance(idea_id) if(idea.discussion != extract.discussion): raise HTTPBadRequest( "Extract from discussion %s cannot be associated with an idea from a different discussion." % extract.get_discussion_id()) extract.idea = idea else: extract.idea = None Extract.db.add(extract) #TODO: Merge ranges. Sigh. return {'ok': True}
def home_view(request): user_id = authenticated_userid(request) or Everyone context = get_default_context(request) discussion = context["discussion"] canRead = user_has_permission(discussion.id, user_id, P_READ) if not canRead and user_id == Everyone: # User isn't logged-in and discussion isn't public: # redirect to login page login_url = request.route_url( 'contextual_login', discussion_slug=discussion.slug) return HTTPSeeOther(login_url) elif not canRead: # User is logged-in but doesn't have access to the discussion return HTTPUnauthorized() canAddExtract = user_has_permission(context["discussion"].id, user_id, P_ADD_EXTRACT) context['canAddExtract'] = canAddExtract context['canDisplayTabs'] = True response = render_to_response('../../templates/index.jinja2', context, request=request) # Prevent caching the home, especially for proper login/logout response.cache_control.max_age = 0 response.cache_control.prevent_auto = True return response
def home_view(request): """The main view on a discussion""" user_id = authenticated_userid(request) or Everyone context = get_default_context(request) discussion = context["discussion"] canRead = user_has_permission(discussion.id, user_id, P_READ) if not canRead and user_id == Everyone: # User isn't logged-in and discussion isn't public: # redirect to login page # need to pass the route to go to *after* login as well # With regards to a next_view, if explicitly stated, then # that is the next view. If not stated, the referer takes # precedence. In case of failure, login redirects to the # discussion which is its context. next_view = request.params.get('next', None) if not next_view and discussion: # If referred here from a post url, want to be able to # send the user back. Usually, Assembl will send the user # here to login on private discussions. referrer = request.url next_view = path_qs(referrer) if discussion.preferences['authorization_server_backend']: login_url = request.route_url( "contextual_social_auth", discussion_slug=discussion.slug, backend=discussion.preferences['authorization_server_backend'], _query={"next": next_view}) elif next_view: login_url = request.route_url("contextual_login", discussion_slug=discussion.slug, _query={"next": next_view}) else: login_url = request.route_url('contextual_login', discussion_slug=discussion.slug) return HTTPTemporaryRedirect(login_url) elif not canRead: # User is logged-in but doesn't have access to the discussion # Would use render_to_response, except for the 401 from pyramid_jinja2 import IJinja2Environment jinja_env = request.registry.queryUtility(IJinja2Environment, name='.jinja2') template = jinja_env.get_template('cannot_read_discussion.jinja2') body = template.render(get_default_context(request)) return Response(body, 401) # if the route asks for a post, get post content (because this is needed for meta tags) route_name = request.matched_route.name if route_name == "purl_posts": post_id = FrontendUrls.getRequestedPostId(request) if not post_id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) post = Post.get_instance(post_id) if not post or post.discussion_id != discussion.id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) context['post'] = post elif route_name == "purl_idea": idea_id = FrontendUrls.getRequestedIdeaId(request) if not idea_id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) idea = Idea.get_instance(idea_id) if not idea or idea.discussion_id != discussion.id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) context['idea'] = idea canAddExtract = user_has_permission(discussion.id, user_id, P_ADD_EXTRACT) context['canAddExtract'] = canAddExtract context['canDisplayTabs'] = True preferences = discussion.preferences if user_id != Everyone: from assembl.models import UserPreferenceCollection user = User.get(user_id) preferences = UserPreferenceCollection(user_id, discussion) # TODO: user may not exist. Case of session with BD change. user.is_visiting_discussion(discussion.id) session = Discussion.default_db if '_LOCALE_' in request.cookies: locale = request.cookies['_LOCALE_'] process_locale(locale, user, session, LanguagePreferenceOrder.Cookie) elif '_LOCALE_' in request.params: locale = request.params['_LOCALE_'] process_locale(locale, user, session, LanguagePreferenceOrder.Parameter) else: locale = locale_negotiator(request) process_locale(locale, user, session, LanguagePreferenceOrder.OS_Default) else: locale = request.localizer.locale_name target_locale = Locale.get_or_create(strip_country(locale), discussion.db) translation_service_data = {} try: service = discussion.translation_service() if service: translation_service_data = service.serviceData() except: pass context['translation_service_data_json'] = json.dumps( translation_service_data) locale_labels = json.dumps( DummyGoogleTranslationService.target_locale_labels_cls(target_locale)) context['translation_locale_names_json'] = locale_labels context['preferences_json'] = json.dumps(dict(preferences)) response = render_to_response('../../templates/index.jinja2', context, request=request) # Prevent caching the home, especially for proper login/logout response.cache_control.max_age = 0 response.cache_control.prevent_auto = True return response
def discussion_permissions(request): user_id = authenticated_userid(request) assert user_id db = Discussion.default_db discussion_id = int(request.matchdict['discussion_id']) discussion = Discussion.get_instance(discussion_id) error = '' if not discussion: raise HTTPNotFound("Discussion with id '%d' not found." % ( discussion_id,)) roles = db.query(Role).all() roles_by_name = {r.name: r for r in roles} role_names = [r.name for r in roles] role_names.sort() permissions = db.query(Permission).all() perms_by_name = {p.name: p for p in permissions} permission_names = [p.name for p in permissions] permission_names.sort() disc_perms = db.query(DiscussionPermission).filter_by( discussion_id=discussion_id).join(Role, Permission).all() disc_perms_as_set = set((dp.role.name, dp.permission.name) for dp in disc_perms) disc_perms_dict = {(dp.role.name, dp.permission.name): dp for dp in disc_perms} local_roles = db.query(LocalUserRole).filter_by( discussion_id=discussion_id).join(Role, User).all() local_roles_as_set = set((lur.user.id, lur.role.name) for lur in local_roles) local_roles_dict = {(lur.user.id, lur.role.name): lur for lur in local_roles} users = set(lur.user for lur in local_roles) num_users = '' if request.POST: if 'submit_role_permissions' in request.POST: for role in role_names: if role == R_SYSADMIN: continue for permission in permission_names: allowed_text = 'allowed_%s_%s' % (role, permission) if (role, permission) not in disc_perms_as_set and \ allowed_text in request.POST: dp = DiscussionPermission( role=roles_by_name[role], permission=perms_by_name[permission], discussion_id=discussion_id) disc_perms_dict[(role, permission)] = dp disc_perms_as_set.add((role, permission)) db.add(dp) elif (role, permission) in disc_perms_as_set and \ allowed_text not in request.POST: dp = disc_perms_dict[(role, permission)] del disc_perms_dict[(role, permission)] disc_perms_as_set.remove((role, permission)) db.delete(dp) if not role in SYSTEM_ROLES and\ 'delete_'+role in request.POST: db.delete(roles_by_name[role]) del roles_by_name[role] role_names.remove(role) elif 'submit_add_role' in request.POST: #TODO: Sanitize role role = Role(name='r:'+request.POST['new_role']) roles_by_name[role.name] = role role_names.append(role.name) db.add(role) elif 'submit_user_roles' in request.POST: user_ids = {u.id for u in users} for role in role_names: if role == R_SYSADMIN: continue prefix = 'has_'+role+'_' for name in request.POST: if name.startswith(prefix): a_user_id = int(name[len(prefix):]) if a_user_id not in user_ids: users.add(User.get_instance(a_user_id)) user_ids.add(a_user_id) for user in users: has_role_text = 'has_%s_%d' % (role, user.id) if (user.id, role) not in local_roles_as_set and \ has_role_text in request.POST: lur = LocalUserRole( role=roles_by_name[role], user=user, discussion_id=discussion_id) local_roles.append(lur) # TODO revisit this if Roles and Subscription are # de-coupled if role == 'r:participant': user.update_agent_status_subscribe(discussion) local_roles_dict[(user.id, role)] = lur local_roles_as_set.add((user.id, role)) db.add(lur) elif (user.id, role) in local_roles_as_set and \ has_role_text not in request.POST: lur = local_roles_dict[(user.id, role)] del local_roles_dict[(user.id, role)] local_roles_as_set.remove((user.id, role)) local_roles.remove(lur) # TODO revisit this if Roles and Subscription are # de-coupled if role == 'r:participant': user.update_agent_status_unsubscribe(discussion) db.delete(lur) elif 'submit_look_for_user' in request.POST: search_string = '%' + request.POST['user_search'] + '%' other_users = db.query(User).outerjoin(Username).filter( AgentProfile.name.ilike(search_string) | Username.username.ilike(search_string) | User.preferred_email.ilike(search_string)).all() users.update(other_users) elif 'submit_user_file' in request.POST: role = request.POST['add_with_role'] or R_PARTICIPANT if role == R_SYSADMIN and not user_has_permission( discussion_id, user_id, P_SYSADMIN): role = R_ADMINISTRATOR if 'user_csvfile' in request.POST: try: num_users = add_multiple_users_csv( request, request.POST['user_csvfile'].file, discussion_id, role, request.POST.get('send_invite', False), request.POST['email_subject'], request.POST['text_email_message'], request.POST['html_email_message'], request.POST['sender_name'], request.POST.get('resend_notloggedin', False)) except Exception as e: error = repr(e) transaction.doom() else: error = request.localizer.translate(_('No file given.')) def allowed(role, permission): if role == R_SYSADMIN: return True return (role, permission) in disc_perms_as_set def has_local_role(user_id, role): return (user_id, role) in local_roles_as_set users = list(users) users.sort(key=order_by_domain_and_name) context = dict( get_default_context(request), discussion=discussion, allowed=allowed, roles=role_names, permissions=permission_names, users=users, error=error, num_users=num_users, has_local_role=has_local_role, is_system_role=lambda r: r in SYSTEM_ROLES ) return render_to_response( 'admin/discussion_permissions.jinja2', context, request=request)
def post_extract(request): """ Create a new extract. """ extract_data = json.loads(request.body) discussion_id = int(request.matchdict['discussion_id']) user_id = request.authenticated_userid if not user_id: # Straight from annotator token = request.headers.get('X-Annotator-Auth-Token') if token: token = decode_token(token, request.registry.settings['session.secret']) if token: user_id = token['userId'] user_id = user_id or Everyone if not user_has_permission(discussion_id, user_id, P_ADD_EXTRACT): #TODO: maparent: restore this code once it works: #return HTTPForbidden(result=ACLDenied(permission=P_ADD_EXTRACT)) return HTTPForbidden() if not user_id or user_id == Everyone: # TODO: Create an anonymous user. raise HTTPServerError("Anonymous extracts are not implemeted yet.") content = None uri = extract_data.get('uri') important = extract_data.get('important', False) annotation_text = None if uri: # Straight from annotator annotation_text = extract_data.get('text') else: target = extract_data.get('target') if not (target or uri): raise HTTPBadRequest("No target") target_class = sqla.get_named_class(target.get('@type')) if issubclass(target_class, Post): post_id = target.get('@id') post = Post.get_instance(post_id) if not post: raise HTTPNotFound("Post with id '%s' not found." % post_id) content = post elif issubclass(target_class, Webpage): uri = target.get('url') if uri and not content: content = Webpage.get_instance(uri) if not content: # TODO: maparent: This is actually a singleton pattern, should be # handled by the AnnotatorSource now that it exists... source = AnnotatorSource.default_db.query( AnnotatorSource).filter_by(discussion_id=discussion_id).filter( cast(AnnotatorSource.name, Unicode) == 'Annotator').first() if not source: source = AnnotatorSource(name='Annotator', discussion_id=discussion_id) content = Webpage(url=uri, discussion_id=discussion_id) extract_body = extract_data.get('quote', '') idea_id = extract_data.get('idIdea', None) if idea_id: idea = Idea.get_instance(idea_id) if (idea.discussion.id != discussion_id): raise HTTPBadRequest( "Extract from discussion %s cannot be associated with an idea from a different discussion." % extract.get_discussion_id()) else: idea = None ranges = extract_data.get('ranges', []) extract_hash = Extract.get_extract_hash( None, u"".join([r['start'] for r in ranges]), u"".join([r['end'] for r in ranges]), u"".join([r['startOffset'] for r in ranges]), u"".join([r['endOffset'] for r in ranges]), content.id) new_extract = Extract(creator_id=user_id, owner_id=user_id, discussion_id=discussion_id, body=extract_body, idea=idea, important=important, annotation_text=annotation_text, content=content, extract_hash=extract_hash) Extract.default_db.add(new_extract) for range_data in ranges: range = TextFragmentIdentifier(extract=new_extract, xpath_start=range_data['start'], offset_start=range_data['startOffset'], xpath_end=range_data['end'], offset_end=range_data['endOffset']) TextFragmentIdentifier.default_db.add(range) Extract.default_db.flush() return {'ok': True, '@id': new_extract.uri()}
def home_view(request): user_id = authenticated_userid(request) or Everyone context = get_default_context(request) discussion = context["discussion"] request.session["discussion"] = discussion.slug canRead = user_has_permission(discussion.id, user_id, P_READ) if not canRead and user_id == Everyone: # User isn't logged-in and discussion isn't public: # redirect to login page login_url = request.route_url('contextual_login', discussion_slug=discussion.slug) return HTTPSeeOther(login_url) elif not canRead: # User is logged-in but doesn't have access to the discussion return HTTPUnauthorized() # if the route asks for a post, get post content (because this is needed for meta tags) route_name = request.matched_route.name if route_name == "purl_posts": post_id = FrontendUrls.getRequestedPostId(request) if not post_id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) post = Post.get_instance(post_id) if not post or post.discussion_id != discussion.id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) context['post'] = post elif route_name == "purl_idea": idea_id = FrontendUrls.getRequestedIdeaId(request) if not idea_id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) idea = Idea.get_instance(idea_id) if not idea or idea.discussion_id != discussion.id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) context['idea'] = idea canAddExtract = user_has_permission(discussion.id, user_id, P_ADD_EXTRACT) context['canAddExtract'] = canAddExtract context['canDisplayTabs'] = True if user_id != Everyone: from assembl.models import AgentProfile user = AgentProfile.get(user_id) # TODO: user may not exist. Case of session with BD change. user.is_visiting_discussion(discussion.id) session = Discussion.default_db current_prefs = session.query(UserLanguagePreference).\ filter_by(user_id = user_id).all() user = session.query(User).filter_by(id=user_id).first() def validate_locale(l): return ensure_locale_has_country(to_posix_format(locale)) if '_LOCALE_' in request.cookies: locale = request.cookies['_LOCALE_'] posix_locale = validate_locale(locale) process_locale(posix_locale, user_id, current_prefs, session, LanguagePreferenceOrder.Cookie) elif '_LOCALE_' in request.params: locale = request.params['_LOCALE_'] posix_locale = validate_locale(locale) process_locale(posix_locale, user_id, current_prefs, session, LanguagePreferenceOrder.Parameter) else: locale = default_locale_negotiator(request) posix_locale = validate_locale(locale) process_locale(posix_locale, user_id, current_prefs, session, LanguagePreferenceOrder.OS_Default) response = render_to_response('../../templates/index.jinja2', context, request=request) # Prevent caching the home, especially for proper login/logout response.cache_control.max_age = 0 response.cache_control.prevent_auto = True return response
def home_view(request): user_id = authenticated_userid(request) or Everyone context = get_default_context(request) discussion = context["discussion"] canRead = user_has_permission(discussion.id, user_id, P_READ) if not canRead and user_id == Everyone: # User isn't logged-in and discussion isn't public: # redirect to login page login_url = request.route_url( 'contextual_login', discussion_slug=discussion.slug) return HTTPSeeOther(login_url) elif not canRead: # User is logged-in but doesn't have access to the discussion return HTTPUnauthorized() # if the route asks for a post, get post content (because this is needed for meta tags) route_name = request.matched_route.name if route_name == "purl_posts": post_id = FrontendUrls.getRequestedPostId(request) if post_id: post = Post.get_instance(post_id) if post and post.discussion_id == discussion.id: context['post'] = post elif route_name == "purl_idea": idea_id = FrontendUrls.getRequestedIdeaId(request) if idea_id: idea = Idea.get_instance(idea_id) if idea and idea.discussion_id == discussion.id: context['idea'] = idea canAddExtract = user_has_permission(discussion.id, user_id, P_ADD_EXTRACT) context['canAddExtract'] = canAddExtract context['canDisplayTabs'] = True if user_id != Everyone: from assembl.models import AgentProfile user = AgentProfile.get(user_id) # TODO: user may not exist. Case of session with BD change. user.is_visiting_discussion(discussion.id) session = Discussion.db() current_prefs = session.query(UserLanguagePreference).\ filter_by(user_id = user_id).all() user = session.query(User).filter_by(id = user_id).first() if '_LOCALE_' in request.cookies: locale = request.cookies['_LOCALE_'] posix_locale = to_posix_format(locale) process_locale(posix_locale,user_id, current_prefs, session, LanguagePreferenceOrder.Cookie) elif '_LOCALE_' in request.params: locale = request.params['_LOCALE_'] posix_locale = to_posix_format(locale) process_locale(posix_locale, user_id, current_prefs, session, LanguagePreferenceOrder.Parameter) else: locale = default_locale_negotiator(request) posix_locale = to_posix_format(locale) process_locale(posix_locale, user_id, current_prefs, session, LanguagePreferenceOrder.OS_Default) response = render_to_response('../../templates/index.jinja2', context, request=request) # Prevent caching the home, especially for proper login/logout response.cache_control.max_age = 0 response.cache_control.prevent_auto = True return response
def discussion_permissions(request): user_id = authenticated_userid(request) assert user_id db = Discussion.default_db discussion_id = int(request.matchdict['discussion_id']) discussion = Discussion.get_instance(discussion_id) error = '' if not discussion: raise HTTPNotFound("Discussion with id '%d' not found." % (discussion_id, )) roles = db.query(Role).all() roles_by_name = {r.name: r for r in roles} role_names = [r.name for r in roles] role_names.sort() permissions = db.query(Permission).all() perms_by_name = {p.name: p for p in permissions} permission_names = [p.name for p in permissions] permission_names.sort() disc_perms = db.query(DiscussionPermission).filter_by( discussion_id=discussion_id).join(Role, Permission).all() disc_perms_as_set = set( (dp.role.name, dp.permission.name) for dp in disc_perms) disc_perms_dict = {(dp.role.name, dp.permission.name): dp for dp in disc_perms} local_roles = db.query(LocalUserRole).filter_by( discussion_id=discussion_id).join(Role, User).all() local_roles_as_set = set( (lur.user.id, lur.role.name) for lur in local_roles) local_roles_dict = {(lur.user.id, lur.role.name): lur for lur in local_roles} users = set(lur.user for lur in local_roles) num_users = '' if request.POST: if 'submit_role_permissions' in request.POST: for role in role_names: if role == R_SYSADMIN: continue for permission in permission_names: allowed_text = 'allowed_%s_%s' % (role, permission) if (role, permission) not in disc_perms_as_set and \ allowed_text in request.POST: dp = DiscussionPermission( role=roles_by_name[role], permission=perms_by_name[permission], discussion_id=discussion_id) disc_perms_dict[(role, permission)] = dp disc_perms_as_set.add((role, permission)) db.add(dp) elif (role, permission) in disc_perms_as_set and \ allowed_text not in request.POST: dp = disc_perms_dict[(role, permission)] del disc_perms_dict[(role, permission)] disc_perms_as_set.remove((role, permission)) db.delete(dp) if not role in SYSTEM_ROLES and\ 'delete_'+role in request.POST: db.delete(roles_by_name[role]) del roles_by_name[role] role_names.remove(role) elif 'submit_add_role' in request.POST: #TODO: Sanitize role role = Role(name='r:' + request.POST['new_role']) roles_by_name[role.name] = role role_names.append(role.name) db.add(role) elif 'submit_user_roles' in request.POST: user_ids = {u.id for u in users} for role in role_names: if role == R_SYSADMIN: continue prefix = 'has_' + role + '_' for name in request.POST: if name.startswith(prefix): a_user_id = int(name[len(prefix):]) if a_user_id not in user_ids: users.add(User.get_instance(a_user_id)) user_ids.add(a_user_id) for user in users: has_role_text = 'has_%s_%d' % (role, user.id) if (user.id, role) not in local_roles_as_set and \ has_role_text in request.POST: lur = LocalUserRole(role=roles_by_name[role], user=user, discussion_id=discussion_id) local_roles.append(lur) # TODO revisit this if Roles and Subscription are # de-coupled if role == 'r:participant': user.update_agent_status_subscribe(discussion) local_roles_dict[(user.id, role)] = lur local_roles_as_set.add((user.id, role)) db.add(lur) elif (user.id, role) in local_roles_as_set and \ has_role_text not in request.POST: lur = local_roles_dict[(user.id, role)] del local_roles_dict[(user.id, role)] local_roles_as_set.remove((user.id, role)) local_roles.remove(lur) # TODO revisit this if Roles and Subscription are # de-coupled if role == 'r:participant': user.update_agent_status_unsubscribe(discussion) db.delete(lur) elif 'submit_look_for_user' in request.POST: search_string = '%' + request.POST['user_search'] + '%' other_users = db.query(User).outerjoin(Username).filter( AgentProfile.name.ilike(search_string) | Username.username.ilike(search_string) | User.preferred_email.ilike(search_string)).all() users.update(other_users) elif 'submit_user_file' in request.POST: role = request.POST['add_with_role'] or R_PARTICIPANT if role == R_SYSADMIN and not user_has_permission( discussion_id, user_id, P_SYSADMIN): role = R_ADMINISTRATOR if 'user_csvfile' in request.POST: try: num_users = add_multiple_users_csv( request, request.POST['user_csvfile'].file, discussion_id, role, request.POST.get('send_invite', False), request.POST['email_subject'], request.POST['text_email_message'], request.POST['html_email_message'], request.POST['sender_name'], request.POST.get('resend_notloggedin', False)) except Exception as e: error = repr(e) transaction.doom() else: error = request.localizer.translate(_('No file given.')) def allowed(role, permission): if role == R_SYSADMIN: return True return (role, permission) in disc_perms_as_set def has_local_role(user_id, role): return (user_id, role) in local_roles_as_set users = list(users) users.sort(key=order_by_domain_and_name) context = dict(get_default_context(request), discussion=discussion, allowed=allowed, roles=role_names, permissions=permission_names, users=users, error=error, num_users=num_users, has_local_role=has_local_role, is_system_role=lambda r: r in SYSTEM_ROLES) return render_to_response('admin/discussion_permissions.jinja2', context, request=request)
def home_view(request): user_id = authenticated_userid(request) or Everyone context = get_default_context(request) discussion = context["discussion"] request.session["discussion"] = discussion.slug canRead = user_has_permission(discussion.id, user_id, P_READ) if not canRead and user_id == Everyone: # User isn't logged-in and discussion isn't public: # redirect to login page # need to pass the route to go to *after* login as well # With regards to a next_view, if explicitly stated, then # that is the next view. If not stated, the referer takes # precedence. In case of failure, login redirects to the # discussion which is its context. next_view = request.params.get('next_view', None) if not next_view and discussion: # If referred here from a post url, want to be able to # send the user back. Usually, Assembl will send the user # here to login on private discussions. referrer = request.url next_view = path_qs(referrer) if next_view: login_url = request.route_url("contextual_login", discussion_slug=discussion.slug, _query={"next_view": next_view}) else: login_url = request.route_url( 'contextual_login', discussion_slug=discussion.slug) return HTTPSeeOther(login_url) elif not canRead: # User is logged-in but doesn't have access to the discussion # Would use render_to_response, except for the 401 from pyramid_jinja2 import IJinja2Environment jinja_env = request.registry.queryUtility( IJinja2Environment, name='.jinja2') template = jinja_env.get_template('cannot_read_discussion.jinja2') body = template.render(get_default_context(request)) return Response(body, 401) # if the route asks for a post, get post content (because this is needed for meta tags) route_name = request.matched_route.name if route_name == "purl_posts": post_id = FrontendUrls.getRequestedPostId(request) if not post_id: return HTTPSeeOther(request.route_url( 'home', discussion_slug=discussion.slug)) post = Post.get_instance(post_id) if not post or post.discussion_id != discussion.id: return HTTPSeeOther(request.route_url( 'home', discussion_slug=discussion.slug)) context['post'] = post elif route_name == "purl_idea": idea_id = FrontendUrls.getRequestedIdeaId(request) if not idea_id: return HTTPSeeOther(request.route_url( 'home', discussion_slug=discussion.slug)) idea = Idea.get_instance(idea_id) if not idea or idea.discussion_id != discussion.id: return HTTPSeeOther(request.route_url( 'home', discussion_slug=discussion.slug)) context['idea'] = idea canAddExtract = user_has_permission(discussion.id, user_id, P_ADD_EXTRACT) context['canAddExtract'] = canAddExtract context['canDisplayTabs'] = True preferences = discussion.preferences if user_id != Everyone: from assembl.models import UserPreferenceCollection user = User.get(user_id) preferences = UserPreferenceCollection(user_id, discussion) # TODO: user may not exist. Case of session with BD change. user.is_visiting_discussion(discussion.id) session = Discussion.default_db if '_LOCALE_' in request.cookies: locale = request.cookies['_LOCALE_'] process_locale(locale, user, session, LanguagePreferenceOrder.Cookie) elif '_LOCALE_' in request.params: locale = request.params['_LOCALE_'] process_locale(locale, user, session, LanguagePreferenceOrder.Parameter) else: locale = locale_negotiator(request) process_locale(locale, user, session, LanguagePreferenceOrder.OS_Default) else: locale = request.localizer.locale_name target_locale = Locale.get_or_create( strip_country(locale), discussion.db) translation_service_data = {} try: service = discussion.translation_service() if service: translation_service_data = service.serviceData() except: pass context['translation_service_data_json'] = json.dumps( translation_service_data) locale_labels = json.dumps( DummyGoogleTranslationService.target_locale_labels_cls(target_locale)) context['translation_locale_names_json'] = locale_labels context['preferences_json'] = json.dumps(dict(preferences)) response = render_to_response('../../templates/index.jinja2', context, request=request) # Prevent caching the home, especially for proper login/logout response.cache_control.max_age = 0 response.cache_control.prevent_auto = True return response
def post_extract(request): """ Create a new extract. """ extract_data = json.loads(request.body) discussion_id = int(request.matchdict['discussion_id']) user_id = authenticated_userid(request) if not user_id: # Straight from annotator token = request.headers.get('X-Annotator-Auth-Token') if token: token = decode_token( token, request.registry.settings['session.secret']) if token: user_id = token['userId'] user_id = user_id or Everyone if not user_has_permission(discussion_id, user_id, P_ADD_EXTRACT): #TODO: maparent: restore this code once it works: #return HTTPForbidden(result=ACLDenied(permission=P_ADD_EXTRACT)) return HTTPForbidden() if not user_id or user_id == Everyone: # TODO: Create an anonymous user. raise HTTPServerError("Anonymous extracts are not implemeted yet.") content = None uri = extract_data.get('uri') important = extract_data.get('important', False) annotation_text = None if uri: # Straight from annotator annotation_text = extract_data.get('text') else: target = extract_data.get('target') if not (target or uri): raise HTTPBadRequest("No target") target_class = sqla.get_named_class(target.get('@type')) if issubclass(target_class, Post): post_id = target.get('@id') post = Post.get_instance(post_id) if not post: raise HTTPNotFound( "Post with id '%s' not found." % post_id) content = post elif issubclass(target_class, Webpage): uri = target.get('url') if uri and not content: content = Webpage.get_instance(uri) if not content: # TODO: maparent: This is actually a singleton pattern, should be # handled by the AnnotatorSource now that it exists... source = AnnotatorSource.default_db.query(AnnotatorSource).filter_by( discussion_id=discussion_id).filter( cast(AnnotatorSource.name, Unicode) == 'Annotator').first() if not source: source = AnnotatorSource( name='Annotator', discussion_id=discussion_id, type='source') content = Webpage(url=uri, discussion_id=discussion_id) extract_body = extract_data.get('quote', '') idea_id = extract_data.get('idIdea', None) if idea_id: idea = Idea.get_instance(idea_id) if(idea.discussion.id != discussion_id): raise HTTPBadRequest( "Extract from discussion %s cannot be associated with an idea from a different discussion." % extract.get_discussion_id()) else: idea = None new_extract = Extract( creator_id=user_id, owner_id=user_id, discussion_id=discussion_id, body=extract_body, idea=idea, important=important, annotation_text=annotation_text, content=content ) Extract.default_db.add(new_extract) for range_data in extract_data.get('ranges', []): range = TextFragmentIdentifier( extract=new_extract, xpath_start=range_data['start'], offset_start=range_data['startOffset'], xpath_end=range_data['end'], offset_end=range_data['endOffset']) TextFragmentIdentifier.default_db.add(range) Extract.default_db.flush() return {'ok': True, '@id': new_extract.uri()}
def discussion_permissions(request): user_id = authenticated_userid(request) assert user_id db = Discussion.default_db discussion_id = int(request.matchdict["discussion_id"]) discussion = Discussion.get_instance(discussion_id) error = "" if not discussion: raise HTTPNotFound("Discussion with id '%d' not found." % (discussion_id,)) roles = db.query(Role).all() roles_by_name = {r.name: r for r in roles} role_names = [r.name for r in roles] permissions = db.query(Permission).all() perms_by_name = {p.name: p for p in permissions} permission_names = [p.name for p in permissions] disc_perms = db.query(DiscussionPermission).filter_by(discussion_id=discussion_id).join(Role, Permission).all() disc_perms_as_set = set((dp.role.name, dp.permission.name) for dp in disc_perms) disc_perms_dict = {(dp.role.name, dp.permission.name): dp for dp in disc_perms} local_roles = db.query(LocalUserRole).filter_by(discussion_id=discussion_id).join(Role, User).all() local_roles_as_set = set((lur.user.id, lur.role.name) for lur in local_roles) local_roles_dict = {(lur.user.id, lur.role.name): lur for lur in local_roles} users = set(lur.user for lur in local_roles) num_users = "" if request.POST: if "submit_role_permissions" in request.POST: for role in role_names: if role == R_SYSADMIN: continue for permission in permission_names: allowed_text = "allowed_%s_%s" % (role, permission) if (role, permission) not in disc_perms_as_set and allowed_text in request.POST: dp = DiscussionPermission( role=roles_by_name[role], permission=perms_by_name[permission], discussion_id=discussion_id ) disc_perms_dict[(role, permission)] = dp disc_perms_as_set.add((role, permission)) db.add(dp) elif (role, permission) in disc_perms_as_set and allowed_text not in request.POST: dp = disc_perms_dict[(role, permission)] del disc_perms_dict[(role, permission)] disc_perms_as_set.remove((role, permission)) db.delete(dp) if not role in SYSTEM_ROLES and "delete_" + role in request.POST: db.delete(roles_by_name[role]) del roles_by_name[role] role_names.remove(role) elif "submit_add_role" in request.POST: # TODO: Sanitize role role = Role(name="r:" + request.POST["new_role"]) roles_by_name[role.name] = role role_names.append(role.name) db.add(role) elif "submit_user_roles" in request.POST: user_ids = {u.id for u in users} for role in role_names: if role == R_SYSADMIN: continue prefix = "has_" + role + "_" for name in request.POST: if name.startswith(prefix): a_user_id = int(name[len(prefix) :]) if a_user_id not in user_ids: users.add(User.get_instance(a_user_id)) user_ids.add(a_user_id) for user in users: has_role_text = "has_%s_%d" % (role, user.id) if (user.id, role) not in local_roles_as_set and has_role_text in request.POST: lur = LocalUserRole(role=roles_by_name[role], user=user, discussion_id=discussion_id) local_roles.append(lur) local_roles_dict[(user.id, role)] = lur local_roles_as_set.add((user.id, role)) db.add(lur) elif (user.id, role) in local_roles_as_set and has_role_text not in request.POST: lur = local_roles_dict[(user.id, role)] del local_roles_dict[(user.id, role)] local_roles_as_set.remove((user.id, role)) local_roles.remove(lur) db.delete(lur) elif "submit_look_for_user" in request.POST: search_string = "%" + request.POST["user_search"] + "%" other_users = ( db.query(User) .outerjoin(Username) .filter( AgentProfile.name.ilike(search_string) | Username.username.ilike(search_string) | User.preferred_email.ilike(search_string) ) .all() ) users.update(other_users) elif "submit_user_file" in request.POST: role = request.POST["add_with_role"] or R_PARTICIPANT if role == R_SYSADMIN and not user_has_permission(discussion_id, user_id, P_SYSADMIN): role = R_ADMINISTRATOR if "user_csvfile" in request.POST: try: num_users = add_multiple_users_csv(request.POST["user_csvfile"].file, discussion_id, role) except Exception as e: error = repr(e) else: error = request.localizer.translate(_("No file given.")) def allowed(role, permission): if role == R_SYSADMIN: return True return (role, permission) in disc_perms_as_set def has_local_role(user_id, role): return (user_id, role) in local_roles_as_set context = dict( get_default_context(request), discussion=discussion, allowed=allowed, roles=role_names, permissions=permission_names, users=users, error=error, num_users=num_users, has_local_role=has_local_role, is_system_role=lambda r: r in SYSTEM_ROLES, ) return render_to_response("admin/discussion_permissions.jinja2", context, request=request)