def delete(user_id): """Delete the user with id ``user_id`` If the ``revoke`` property is set to true, then the user will be removed from the whitelist, and not be allowed to make an account again. **Route:** ``/admin/users/delete/<user_id>`` **Methods:** ``POST`` """ object_id = ObjectId(user_id) if User.objects(id=object_id).count() != 1: abort(401) user = User.objects().get(id=object_id) # Update whitelist try: wl = Whitelist.objects().get(email=user.email) wl.redeemed = False wl.save() except DoesNotExist: pass user.delete() # Log out if a user is attempting to delete themselves if 'gplus_id' in session and user.gplus_id == session['gplus_id']: flash('You deleted yourself successfully. Logging out.', MESSAGE_FLASH) return redirect(url_for('.logout'), 303) flash('User deleted successfully.', MESSAGE_FLASH) return redirect(url_for('.index'), code=303)
def lookup_current_user(): """Set the g.user variable to the User in the database that shares openid with the session, if one exists. Note that it gets called before all requests, but not before decorators """ g.user = None if not current_app.config.get('EVENTUM_GOOGLE_AUTH_ENABLED'): # bypass auth by mocking a super user session['gplus_id'] = SUPER_USER_GPLUS_ID try: g.user = User.objects.get(gplus_id=SUPER_USER_GPLUS_ID) except DoesNotExist: user = User(name='Super User', gplus_id=SUPER_USER_GPLUS_ID, user_type='admin', email='*****@*****.**') user.save() if 'gplus_id' in session: gplus_id = session['gplus_id'] try: g.user = User.objects().get(gplus_id=gplus_id) except DoesNotExist: pass # Fail gracefully if the user is not in the database yet
def setUpClass(cls): # noqa """Sets up a test database before each set of tests.""" cls.app = create_app( MONGODB_SETTINGS={'DB': 'testing'}, TESTING=True, CSRF_ENABLED=False, WTF_CSRF_ENABLED=False ) from eventum.models import User User.drop_collection()
def register_delete_rules(self): """Registers rules for how Mongoengine handles the deletion of objects that are being referenced by other objects. See the documentation for :func:`mongoengine.model.register_delete_rule` for more information. All delete rules for User fields must by DENY, because User objects should never be deleted. Lists of reference fields should PULL, to remove deleted objects from the list, and all others should NULLIFY """ from eventum.models import (Event, EventSeries, User, Post, BlogPost, Image) from mongoengine import NULLIFY, PULL, DENY Event.register_delete_rule(EventSeries, 'events', PULL) Image.register_delete_rule(BlogPost, 'images', PULL) Image.register_delete_rule(User, 'image', NULLIFY) Image.register_delete_rule(BlogPost, 'featured_image', NULLIFY) Image.register_delete_rule(Event, 'image', NULLIFY) EventSeries.register_delete_rule(Event, 'parent_series', NULLIFY) User.register_delete_rule(Event, 'creator', DENY) User.register_delete_rule(Image, 'creator', DENY) User.register_delete_rule(Post, 'author', DENY) User.register_delete_rule(Post, 'posted_by', DENY)
def import_from_directory(path_to_images): connect("eventum") creator = User.objects().get(gplus_id="super") filenames = os.listdir(path_to_images) filenames = [fn for fn in filenames if not fn.startswith(".")] failures = [] for filename in filenames: if Image.objects(filename=filename).count() > 0: img = Image.objects().get(filename=filename) img.delete() old_path = os.path.join(path_to_images, filename) shutil.copy(old_path, config["UPLOAD_FOLDER"]) default_path = config["RELATIVE_UPLOAD_FOLDER"] + filename image = Image(filename=filename, default_path=default_path, creator=creator) try: image.save() except ValidationError as e: failures.append(filename) print "FAIL: %s" % filename print e print "Processed %s images." % len(filenames) print "%s success." % (len(filenames) - len(failures)) print "%s failures." % len(failures)
def user(slug): """View and edit the profile of a user. **Route:** ``/admin/user/<slug>`` **Methods:** ``GET, POST`` """ try: user = User.objects().get(slug=slug) except DoesNotExist: flash("Invalid user slug '{}'".format(slug), ERROR_FLASH) return redirect(url_for('.index')) form = EditUserForm( request.form, name=user.name, email=user.email, # image_url=user.get_profile_picture(), user_type=user.user_type) if request.method == 'POST': if form.validate_on_submit(): user.name = form.name.data user.email = form.email.data user.user_type = form.user_type.data # user.image_url = form.image_url.data user.save() return redirect(url_for('.index')) else: flash("Your Form had errors: {}".format(form.errors), ERROR_FLASH) return render_template('eventum_users/user.html', user=user, form=form, current_user=g.user)
def user(slug): """View and edit the profile of a user. **Route:** ``/admin/user/<slug>`` **Methods:** ``GET, POST`` """ try: user = User.objects().get(slug=slug) except DoesNotExist: flash("Invalid user slug '{}'".format(slug), ERROR_FLASH) return redirect(url_for('.index')) form = EditUserForm(request.form, name=user.name, email=user.email, # image_url=user.get_profile_picture(), user_type=user.user_type) if request.method == 'POST': if form.validate_on_submit(): user.name = form.name.data user.email = form.email.data user.user_type = form.user_type.data # user.image_url = form.image_url.data user.save() return redirect(url_for('.index')) else: flash("Your Form had errors: {}".format(form.errors), ERROR_FLASH) return render_template('eventum_users/user.html', user=user, form=form, current_user=g.user)
def become(level=0): """Change the privileges of the logged in user. **Route:** ``/admin/become`` **Methods:** ``GET`` :param int level: 1: Editor, 2: Publisher, 3: Admin """ level = int(level) admin_privileges = { "edit": level > 0, "publish": level > 1, "admin": level > 2 } db_dict = dict((("set__privileges__{}".format(k), v) for k, v in admin_privileges.iteritems())) User.objects(gplus_id=session['gplus_id']).update(**db_dict) return redirect(url_for('.index'))
def new(): """Create a new blog post. **Route:** ``/admin/posts/new`` **Methods:** ``POST`` """ form = CreateBlogPostForm(request.form) form.author.choices = [(str(u.id), u.name + " (You)" if u == g.user else u.name) for u in User.objects()] form.author.data = str(g.user.id) upload_form = UploadImageForm() if form.validate_on_submit(): author = User.objects().get(id=ObjectId(form.author.data)) images = [Image.objects().get(filename=fn) for fn in form.images.data] tags = Tag.get_or_create_tags(form.tags.data) post = BlogPost(title=form.title.data, slug=form.slug.data, images=images, markdown_content=form.body.data, author=author, posted_by=g.user, post_tags=tags) post.save() if form.published.data: post.publish() else: post.unpublish() if form.preview.data is True: return redirect(url_for('blog.preview', slug=post.slug)) return redirect(url_for('.index')) images = Image.objects() return render_template('eventum_posts/edit.html', user=g.user, form=form, images=images, upload_form=upload_form)
def new(): """Create a new blog post. **Route:** ``/admin/posts/new`` **Methods:** ``POST`` """ form = CreateBlogPostForm(request.form) form.author.choices = [ (str(u.id), u.name + " (You)" if u == g.user else u.name) for u in User.objects() ] form.author.data = str(g.user.id) upload_form = UploadImageForm() if form.validate_on_submit(): author = User.objects().get(id=ObjectId(form.author.data)) images = [Image.objects().get(filename=fn) for fn in form.images.data] tags = Tag.get_or_create_tags(form.tags.data) post = BlogPost(title=form.title.data, slug=form.slug.data, images=images, markdown_content=form.body.data, author=author, posted_by=g.user, post_tags=tags) post.save() if form.published.data: post.publish() else: post.unpublish() if form.preview.data is True: return redirect(url_for('blog.preview', slug=post.slug)) return redirect(url_for('.index')) images = Image.objects() return render_template('eventum_posts/edit.html', user=g.user, form=form, images=images, upload_form=upload_form)
def create_profile(): """Create a profile (filling in the form with openid data), and register it in the database. **Route:** ``/admin/create-profile`` **Methods:** ``GET, POST`` """ if g.user is not None and 'gplus_id' in session: # use code=303 to avoid POSTing to the next page. return redirect(url_for('admin.index'), code=303) form = CreateProfileForm(request.form, name=request.args['name'], email=request.args['email'], next=request.args['next']) if form.validate_on_submit(): if User.objects(email=form.email.data).count() != 0: # A user with this email already exists. Override it. user = User.objects.get(email=form.email.data) user.openid = session['openid'] user.name = form.name.data flash('Account with this email already exists. Overridden.', MESSAGE_FLASH) user.register_login() user.save() else: # Retreive their user type from the whitelist then remove them. wl = Whitelist.objects().get(email=form.email.data) user_type = wl.user_type wl.redeemed = True wl.save() # Create a brand new user user = User(email=form.email.data, name=form.name.data, gplus_id=session['gplus_id'], user_type=user_type, image_url=request.args.get('image_url')) flash('Account created successfully.', MESSAGE_FLASH) user.register_login() user.save() # redirect to the next url or the root of the application ('/') if form.next.data: # use code=303 to avoid POSTing to the next page. return redirect(form.next.data, code=303) # use code=303 to avoid POSTing to the next page. return redirect('/', code=303) return render_template('eventum_auth/create_profile.html', image_url=request.args.get('image_url'), form=form)
def index(): """View and manage users. Whitelisted users are the only ones allowed to make user accounts. **Route:** ``/admin/users`` **Methods:** ``GET`` """ upload_form = UploadImageForm() whitelist_form = AddToWhitelistForm() return render_template('eventum_users/users.html', whitelist_form=whitelist_form, upload_form=upload_form, whitelist=Whitelist.objects(redeemed=False), users=User.objects(), images=Image.objects(), current_user=g.user)
def backfill_from_jekyll(path_to_jekyll_posts): connect('eventum') author = User.objects().get(gplus_id='super') filenames = os.listdir(path_to_jekyll_posts) for filename in filenames: slug = filename.split('.')[0] title = None date_published = None published = True markdown_content = '' with open(os.path.join(path_to_jekyll_posts, filename)) as md_file: content = False for line in md_file: if not title and line.startswith('## '): title = line.replace('## ', '').strip() elif not date_published and line.startswith('### '): datestring = line.replace('### ', '').strip() date_published = datetime.strptime(datestring, '%d %b %Y') content = True elif content: markdown_content += line if BlogPost.objects(slug=slug).count() > 0: bp = BlogPost.objects().get(slug=slug) bp.delete() blog_post = BlogPost(title=title, date_published=date_published, published=published, markdown_content=markdown_content, slug=slug, author=author) blog_post.save() print "Backfilled %s blog posts." % len(filenames)
def run(self): """Run the generation. Uses the configurations passed to func:`__init__`. """ # Setup: db connection, superuser, and printer. connect(config['MONGODB_SETTINGS']['DB']) try: superuser = User.objects().get(gplus_id='super') except DoesNotExist: print ('Failed to get superuser. Try running:\n' '\texport GOOGLE_AUTH_ENABLED=TRUE') printer = ProgressPrinter(self.quiet) # Images if self.should_gen_images: if self.wipe: self.warn('Image') print CLIColor.warning('Wiping Image database.') Image.drop_collection() create_images(12, superuser, printer) # Blog posts if self.should_gen_posts: if self.wipe: self.warn('BlogPost') print CLIColor.warning('Wiping BlogPost database.') BlogPost.drop_collection() create_posts(10, superuser, printer) # Events and event series if self.should_gen_events: if self.wipe: self.warn('Event and EventSeries') print CLIColor.warning('Wiping Event database.') Event.drop_collection() print CLIColor.warning('Wiping EventSeries database.') EventSeries.drop_collection() create_events(superuser, printer)
def add(): """Add and email to the whitelist. **Route:** ``/admin/whitelist/add`` **Methods:** ``POST`` """ form = AddToWhitelistForm(request.form) if form.user_type.data == 'fake_user': if form.validate_on_submit(): fake_id = str(uuid.uuid4()) fake_email = fake_id[:10] + "@fake-users.com" filename = form.fake_user_image.data try: fake_image = Image.objects().get(filename=filename) fake_user = User(email=fake_email, gplus_id=fake_id, name=form.name.data, user_type=form.user_type.data, image=fake_image) except Image.DoesNotExist: fake_user = User(email=fake_email, gplus_id=fake_id, name=form.name.data, user_type=form.user_type.data) fake_user.save() else: current_app.logger.warning(form.errors) else: user_exists = User.objects(email=form.email.data).count() != 0 if form.validate_on_submit() and not user_exists: wl = Whitelist(email=form.email.data, user_type=form.user_type.data) wl.save() else: current_app.logger.warning(form.errors) return redirect(url_for('users.index'))
def tearDown(self): # noqa """After every test, delete users created in :func:`setUp`.""" from eventum.models import User User.drop_collection()
def store_token(): """Do the oauth flow for Google plus sign in, storing the access token in the session, and redircting to create an account if appropriate. Because this method will be called from a ``$.ajax()`` request in JavaScript, we can't return ``redirect()``, so instead this method returns the URL that the user should be redirected to, and the redirect happens in html: .. code:: javascript success: function(response) { window.location.href = response.data.redirect_url; } **Route:** ``/admin/store-token`` **Methods:** ``POST`` """ if request.args.get('state', '') != session.get('state'): return json_error_message('Invalid state parameter.', 401) del session['state'] code = request.data try: # Upgrade the authorization code into a credentials object oauth_flow = flow_from_clientsecrets( current_app.config['EVENTUM_CLIENT_SECRETS_PATH'], scope='') oauth_flow.redirect_uri = 'postmessage' credentials = oauth_flow.step2_exchange(code) except FlowExchangeError: return json_error_message('Failed to upgrade the authorization code.', 401) gplus_id = credentials.id_token['sub'] # Store the access token in the session for later use. session['credentials'] = credentials.access_token session['gplus_id'] = gplus_id if User.objects(gplus_id=gplus_id).count() == 0: # A new user model must be made # Get the user's name and email to populate the form http = httplib2.Http() http = credentials.authorize(http) people_document = gplus_service.people().get(userId='me').execute( http=http) # The user must be whitelisted in order to create an account. email = people_document['emails'][0]['value'] if Whitelist.objects(email=email).count() != 1: return json_error_message('User has not been whitelisted.', 401, { 'whitelisted': False, 'email': email }) return json_success({ 'redirect_url': url_for('.create_profile', next=request.args.get('next'), name=people_document['displayName'], email=email, image_url=people_document['image']['url']) }) user = User.objects().get(gplus_id=gplus_id) user.register_login() user.save() # The user already exists. Redirect to the next url or # the root of the application ('/') if request.args.get('next'): return json_success({'redirect_url': request.args.get('next')}) return json_success({'redirect_url': request.url_root})
def setUp(self): # noqa """Before every test, make some example users.""" from eventum.models import User for user_config in USERS.values(): user = User(**user_config) user.save()
def store_token(): """Do the oauth flow for Google plus sign in, storing the access token in the session, and redircting to create an account if appropriate. Because this method will be called from a ``$.ajax()`` request in JavaScript, we can't return ``redirect()``, so instead this method returns the URL that the user should be redirected to, and the redirect happens in html: .. code:: javascript success: function(response) { window.location.href = response.data.redirect_url; } **Route:** ``/admin/store-token`` **Methods:** ``POST`` """ if request.args.get('state', '') != session.get('state'): return json_error_message('Invalid state parameter.', 401) del session['state'] code = request.data try: # Upgrade the authorization code into a credentials object oauth_flow = flow_from_clientsecrets( current_app.config['EVENTUM_CLIENT_SECRETS_PATH'], scope='') oauth_flow.redirect_uri = 'postmessage' credentials = oauth_flow.step2_exchange(code) except FlowExchangeError: return json_error_message('Failed to upgrade the authorization code.', 401) gplus_id = credentials.id_token['sub'] # Store the access token in the session for later use. session['credentials'] = credentials.access_token session['gplus_id'] = gplus_id if User.objects(gplus_id=gplus_id).count() == 0: # A new user model must be made # Get the user's name and email to populate the form http = httplib2.Http() http = credentials.authorize(http) people_document = gplus_service.people().get( userId='me').execute(http=http) # The user must be whitelisted in order to create an account. email = people_document['emails'][0]['value'] if Whitelist.objects(email=email).count() != 1: return json_error_message('User has not been whitelisted.', 401, {'whitelisted': False, 'email': email}) return json_success({ 'redirect_url': url_for('.create_profile', next=request.args.get('next'), name=people_document['displayName'], email=email, image_url=people_document['image']['url']) }) user = User.objects().get(gplus_id=gplus_id) user.register_login() user.save() # The user already exists. Redirect to the next url or # the root of the application ('/') if request.args.get('next'): return json_success({'redirect_url': request.args.get('next')}) return json_success({'redirect_url': request.url_root})
def edit(post_id): """Edit an existing blog post. **Route:** ``/admin/posts/edit/<post_id>`` **Methods:** ``GET, POST`` :param str post_id: The ID of the post to edit. """ try: object_id = ObjectId(post_id) except InvalidId: return abort(404) try: post = BlogPost.objects().with_id(object_id) except (DoesNotExist, ValidationError): flash('Cannot find blog post with id {}.'.format(post_id), ERROR_FLASH) return redirect(url_for('.index')) if request.method == 'POST': form = CreateBlogPostForm(request.form) form.author.choices = [(str(u.id), u.name + " (You)" if u == g.user else u.name) for u in User.objects()] form.author.default = str(g.user.id) if form.validate_on_submit(): post.title = form.title.data post.author = User.objects.get(id=ObjectId(form.author.data)) post.slug = form.slug.data post.markdown_content = form.body.data post.images = [ Image.objects().get(filename=fn) for fn in form.images.data ] post.post_tags = Tag.get_or_create_tags(form.tags.data) if form.featured_image.data: post.featured_image = Image.objects().get( filename=form.featured_image.data) else: post.featured_image = None post.save() if post.published != form.published.data: if form.published.data: post.publish() flash('Blogpost published', MESSAGE_FLASH) else: post.unpublish() flash('Blogpost unpublished', MESSAGE_FLASH) if form.preview.data is True: return redirect(url_for('blog.preview', slug=post.slug)) upload_form = UploadImageForm() feat_img = post.featured_image.filename if post.featured_image else None form = CreateBlogPostForm(request.form, title=post.title, slug=post.slug, published=post.published, body=post.markdown_content, images=[image.filename for image in post.images], author=str(post.author.id), featured_image=feat_img, tags=post.post_tags) form.author.choices = [(str(u.id), u.name + " (You)" if u == g.user else u.name) for u in User.objects()] form.author.default = str(g.user.id) images = [image for image in Image.objects() if image not in post.images] return render_template('eventum_posts/edit.html', user=g.user, form=form, post=post, images=images, upload_form=upload_form)
def edit(post_id): """Edit an existing blog post. **Route:** ``/admin/posts/edit/<post_id>`` **Methods:** ``GET, POST`` :param str post_id: The ID of the post to edit. """ try: object_id = ObjectId(post_id) except InvalidId: return abort(404) try: post = BlogPost.objects().with_id(object_id) except (DoesNotExist, ValidationError): flash('Cannot find blog post with id {}.'.format(post_id), ERROR_FLASH) return redirect(url_for('.index')) if request.method == 'POST': form = CreateBlogPostForm(request.form) form.author.choices = [ (str(u.id), u.name + " (You)" if u == g.user else u.name) for u in User.objects()] form.author.default = str(g.user.id) if form.validate_on_submit(): post.title = form.title.data post.author = User.objects.get(id=ObjectId(form.author.data)) post.slug = form.slug.data post.markdown_content = form.body.data post.images = [ Image.objects().get(filename=fn) for fn in form.images.data ] post.post_tags = Tag.get_or_create_tags(form.tags.data) if form.featured_image.data: post.featured_image = Image.objects().get( filename=form.featured_image.data) else: post.featured_image = None post.save() if post.published != form.published.data: if form.published.data: post.publish() flash('Blogpost published', MESSAGE_FLASH) else: post.unpublish() flash('Blogpost unpublished', MESSAGE_FLASH) if form.preview.data is True: return redirect(url_for('blog.preview', slug=post.slug)) upload_form = UploadImageForm() feat_img = post.featured_image.filename if post.featured_image else None form = CreateBlogPostForm(request.form, title=post.title, slug=post.slug, published=post.published, body=post.markdown_content, images=[image.filename for image in post.images], author=str(post.author.id), featured_image=feat_img, tags=post.post_tags) form.author.choices = [ (str(u.id), u.name + " (You)" if u == g.user else u.name) for u in User.objects() ] form.author.default = str(g.user.id) images = [image for image in Image.objects() if image not in post.images] return render_template('eventum_posts/edit.html', user=g.user, form=form, post=post, images=images, upload_form=upload_form)