def new(): """ Create a new project. """ form = ProjectDetailsForm() if form.validate_on_submit(): p = Project.by_name_and_owner(form.name.data, g.user) if p: form.name.errors = [wtf.ValidationError("Project name must be unique.")] else: p = Project.new(form.name.data, public=form.public.data, website=form.website.data) p.full_name = "{0}/{1}".format(g.user.username, p.name) g.user.projects.append(p) g.db.session.add(p) if p.public: # New public projects get added to #commits by default. c = Channel.new("#commits", "irc.freenode.net", 6667, ssl=False, public=True) p.channels.append(c) g.db.session.commit() flash("Your project has been created.", "success") return redirect(url_for(".details", u=g.user.username, p=p.name)) return render_template("new_project.html", form=form)
def new(): """ Create a new project. """ form = ProjectDetailsForm() if form.validate_on_submit(): p = Project.by_name_and_owner(form.name.data, g.user) if p: form.name.errors = [ wtf.ValidationError('Project name must be unique.') ] else: p = Project.new( form.name.data, public=form.public.data, website=form.website.data ) p.full_name = '{0}/{1}'.format(g.user.username, p.name) g.db.session.add(p) g.user.projects.append(p) g.db.session.commit() flash('Your project has been created.', 'success') return redirect(url_for('.overview', u=g.user.username)) return render_template('new_project.html', form=form)
def new(): """ Create a new project. """ form = ProjectDetailsForm() if form.validate_on_submit(): p = Project.by_name_and_owner(form.name.data, g.user) if p: form.name.errors = [ wtf.ValidationError('Project name must be unique.') ] else: p = Project.new(form.name.data, public=form.public.data, website=form.website.data) p.full_name = '{0}/{1}'.format(g.user.username, p.name) g.user.projects.append(p) db.session.add(p) if p.public: # New public projects get added to #commits by default. c = Channel.new('#commits', 'chat.freenode.net', 6667, ssl=False, public=True) p.channels.append(c) db.session.commit() return redirect(url_for('.details', u=g.user.username, p=p.name)) return render_template('new_project.html', form=form)
def edit_project(u, p): """ Edit an existing project. """ if p.owner.id != g.user.id: # Project isn't public and the viewer isn't the project owner. # (403 Forbidden) return abort(403) form = ProjectDetailsForm(obj=p) if form.validate_on_submit(): old_p = Project.by_name_and_owner(form.name.data, g.user) if old_p and old_p.id != p.id: form.name.errors = [ wtf.ValidationError('Project name must be unique.') ] else: p.name = form.name.data p.website = form.website.data p.public = form.public.data p.full_name = '{0}/{1}'.format(g.user.username, p.name) g.db.session.commit() return redirect(url_for('.dashboard', u=u.username)) return render_template('edit_project.html', project=p, form=form )
def landing(): """ Show a landing page giving a short intro blurb to unregistered users and very basic metrics such as total users. """ # Create a list of total project counts in the form # [(day, count), ...]. projects_graph_data = [] now = datetime.datetime.utcnow() for day_ago in range(30): limit = now - datetime.timedelta(days=day_ago) projects_graph_data.append(( time.mktime(limit.timetuple()) * 1000, Project.query.filter(Project.created <= limit).count() )) # Find the 10 latest public projects. new_projects = ( Project.visible(Project.query, user=g.user) .order_by(False) .order_by(Project.created.desc()) ).paginate(1, 10, False) # Sum the total number of messages across all projects, caching # it for the next two minutes. total_messages = g.redis.get('cache_message_count') if total_messages is None: total_messages = g.db.session.query( func.sum(Project.message_count) ).scalar() if total_messages is None: total_messages = 0 g.redis.setex('cache_message_count', 120, total_messages) # Total # of users. total_users = User.query.count() # Find the 10 most popular networks. top_networks = ( Channel.visible(g.db.session.query( Channel.host, func.count(func.distinct(Channel.channel)).label('count') ), user=g.user) .group_by(Channel.host) .order_by('count desc') ) total_networks = top_networks.count() top_networks = top_networks.limit(10) return render_template( 'landing.html', projects_graph_data=projects_graph_data, new_projects=new_projects, top_networks=top_networks, total_networks=total_networks, total_messages=total_messages, total_users=total_users )
def edit_project(u, p): """ Edit an existing project. """ if p.owner.id != g.user.id: # Project isn't public and the viewer isn't the project owner. # (403 Forbidden) return abort(403) form = ProjectDetailsForm(obj=p) if form.validate_on_submit(): old_p = Project.by_name_and_owner(form.name.data, g.user) if old_p and old_p.id != p.id: form.name.errors = [ wtf.ValidationError('Project name must be unique.') ] else: p.name = form.name.data p.website = form.website.data p.public = form.public.data p.full_name = '{0}/{1}'.format(g.user.username, p.name) db.session.commit() return redirect(url_for('.dashboard', u=u.username)) return render_template('edit_project.html', project=p, form=form)
def new(): """ Create a new project. """ form = ProjectDetailsForm() if form.validate_on_submit(): p = Project.by_name_and_owner(form.name.data, g.user) if p: form.name.errors = [ wtf.ValidationError('Project name must be unique.') ] else: p = Project.new( form.name.data, public=form.public.data, website=form.website.data ) p.full_name = '{0}/{1}'.format(g.user.username, p.name) g.user.projects.append(p) g.db.session.add(p) if p.public: # New public projects get added to #commits by default. c = Channel.new( '#commits', 'irc.freenode.net', 6667, ssl=False, public=True ) p.channels.append(c) g.db.session.commit() return redirect(url_for('.details', u=g.user.username, p=p.name)) return render_template('new_project.html', form=form)
def projects(page=1): per_page = min(int(request.args.get('l', 25)), 100) sort_by = request.args.get('s', 'created') q = Project.visible(Project.query, user=g.user).order_by(False) q = q.order_by({ 'created': Project.created.desc(), 'messages': Project.message_count.desc() }.get(sort_by, Project.created.desc())) pagination = q.paginate(page, per_page, False) return render_template('projects.html', pagination=pagination, per_page=per_page)
def _wrapped(*args, **kwargs): u = User.by_username(kwargs.pop('u')) if not u: # No such user exists. return abort(404) p = Project.by_name_and_owner(kwargs.pop('p'), u) if not p: # Project doesn't exist (404 Not Found) return abort(404) kwargs['p'] = p kwargs['u'] = u return f(*args, **kwargs)
def projects(page=1): per_page = min(int(request.args.get('l', 25)), 100) sort_by = request.args.get('s', 'created') q = Project.visible(Project.query, user=g.user).order_by(False) q = q.order_by({ 'created': Project.created.desc(), 'messages': Project.message_count.desc() }.get(sort_by, Project.created.desc())) pagination = q.paginate(page, per_page, False) return render_template('projects.html', pagination=pagination, per_page=per_page )
def landing(): """ Show a landing page giving a short intro blurb to unregistered users and very basic metrics such as total users. """ # Find the 10 latest public projects. new_projects = (Project.visible(Project.query, user=g.user).order_by(False).order_by( Project.created.desc())).paginate( 1, 10, False) return render_template('landing.html', new_projects=new_projects, top_networks=stats.top_networks(limit=10), total_networks=stats.total_networks(), total_users=stats.total_users())
def landing(): """ Show a landing page giving a short intro blurb to unregistered users and very basic metrics such as total users. """ # Find the 10 latest public projects. new_projects = ( Project.visible(Project.query, user=g.user) .order_by(False) .order_by(Project.created.desc()) ).paginate(1, 10, False) return render_template( 'landing.html', new_projects=new_projects, top_networks=stats.top_networks(limit=10), total_networks=stats.total_networks(), total_users=stats.total_users() )
def edit_project(u, p): """ Edit an existing project. """ if p.owner.id != g.user.id: # Project isn't public and the viewer isn't the project owner. # (403 Forbidden) return abort(403) form = ProjectDetailsForm(obj=p) if form.validate_on_submit(): old_p = Project.by_name_and_owner(form.name.data, g.user) if old_p and old_p.id != p.id: form.name.errors = [wtf.ValidationError("Project name must be unique.")] else: p.name = form.name.data p.website = form.website.data p.public = form.public.data p.full_name = "{0}/{1}".format(g.user.username, p.name) g.db.session.commit() flash("Your changes have been saved.", "success") return redirect(url_for(".overview", u=u.username)) return render_template("edit_project.html", project=p, form=form)
def github(): """ Import/merge the users existing Github projects, optionally setting up web hooks for them. """ if 'code' in request.args: # We've finished step one and have a temporary token. r = requests.post('https://github.com/login/oauth/access_token', params={ 'client_id': app.config['SERVICE_GITHUB_CLIENT_ID'], 'client_secret': app.config['SERVICE_GITHUB_CLIENT_SECRET'], 'code': request.args['code'] }, headers={ 'Accept': 'application/json' }) result = r.json token = AuthToken.new(result['access_token'], 'github') g.db.session.add(token) g.user.tokens.append(token) g.db.session.commit() return redirect(url_for('.github')) # Check to see if the user has previously authenticated. access_token = AuthToken.query.filter_by( name='github', owner_id=g.user.id ).first() if access_token is None: # The user hasn't setup Github yet, we need to get their OAuth # token. return redirect( 'https://github.com/login/oauth/authorize?{0}'.format( urllib.urlencode({ 'client_id': app.config['SERVICE_GITHUB_CLIENT_ID'], 'scope': 'repo' }) ) ) # Set authentication and pull a JSON blob of all their # repos that they have actually created (or forked). # If we leave type as the default ("all") we also get # repos they have permission on, which we probably don't want. git = Github(access_token.token) user_repos = git.get_user().get_repos(type='all') summary = None options_form = GithubForm() if options_form.validate_on_submit(): summary = [] # WTForms "forgets" disabled fields. This should /always/ be True. options_form.projects.data = True for repo in user_repos: # User didn't check the box, don't import this project. # A hack-ish solution to wtform's BooleanField limitation, # or I would be using wtf.FieldList(wtf.BooleanField(...)). if request.form.get(str(repo.id), None) != 'y': continue p = Project.by_name_and_owner(repo.name, g.user) if p is not None: summary.append(( ( 'Skipping {0} as a project with that name already' ' exists.' ).format(repo.name), False )) continue p = Project.new( repo.name, public=not repo.private, website=repo.homepage ) p.full_name = '{0}/{1}'.format(g.user.username, p.name) g.user.projects.append(p) g.db.session.add(p) summary.append(( 'Project {0} created.'.format(repo.name), True )) if options_form.set_hooks.data: # The user wanted us to auto-create web hooks for them. # We need to commit first to generate the project.id. g.db.session.commit() # Create the hook on Notifico's side... h = Hook.new(10) p.hooks.append(h) g.db.session.add(h) # ... then create the hook on Github's side. repo.create_hook('web', { 'url': url_for( 'projects.hook_recieve', pid=p.id, key=h.key, _external=True ) }) g.db.session.commit() return render_template('github.html', options_form=options_form, summary=summary, user_repos=user_repos )
def github(): """ Import/merge the users existing Github projects, optionally setting up web hooks for them. """ if 'code' in request.args: # We've finished step one and have a temporary token. r = requests.post('https://github.com/login/oauth/access_token', params={ 'client_id': app.config['SERVICE_GITHUB_CLIENT_ID'], 'client_secret': app.config['SERVICE_GITHUB_CLIENT_SECRET'], 'code': request.args['code'] }, headers={ 'Accept': 'application/json' }) result = r.json() token = AuthToken.new(result['access_token'], 'github') g.db.session.add(token) g.user.tokens.append(token) g.db.session.commit() return redirect(url_for('.github')) # Check to see if the user has previously authenticated. access_token = AuthToken.query.filter_by( name='github', owner_id=g.user.id ).first() if access_token is None: # The user hasn't setup Github yet, we need to get their OAuth # token. return redirect( 'https://github.com/login/oauth/authorize?{0}'.format( urllib.urlencode({ 'client_id': app.config['SERVICE_GITHUB_CLIENT_ID'], 'scope': 'repo' }) ) ) # Set authentication and pull a JSON blob of all their # repos that they have actually created (or forked). # If we leave type as the default ("all") we also get # repos they have permission on, which we probably don't want. git = Github(access_token.token) # Test to make sure our token is still good... try: git.get_user().login except GithubException as exception: # Nope! if exception.status == 401: # The user almost certainly removed the OAuth token # from their github applications page. Remove the now-obsolete # token and refresh. access_token = AuthToken.query.filter_by( name='github', owner_id=g.user.id ).first() if access_token: g.user.tokens.remove(access_token) g.db.session.delete(access_token) g.db.session.commit() return redirect(request.path) user = git.get_user() # Get all of the users own repositories user_repos = user.get_repos(type='all') # ... and get all of the repos in the users organizations ... all_repos = chain(user_repos, *[o.get_repos() for o in user.get_orgs()]) admin_repos = (r for r in all_repos if r.permissions.admin) summary = None options_form = GithubForm() if options_form.validate_on_submit(): summary = [] for repo in admin_repos: # User didn't check the box, don't import this project. # A hack-ish solution to wtform's BooleanField limitation, # or I would be using wtf.FieldList(wtf.BooleanField(...)). if request.form.get(str(repo.id), None) != 'y': continue # Make sure this project doesn't already exists. p = Project.by_name_and_owner(repo.name, g.user) if p is None: p = Project.new( repo.name, public=not repo.private, website=repo.homepage ) p.full_name = '{0}/{1}'.format(g.user.username, p.name) g.user.projects.append(p) g.db.session.add(p) # We need to commit to generate the project.id which is # used for the following steps. g.db.session.commit() summary.append(( 'Project {0} created.'.format(repo.name), True )) elif p is not None and not options_form.update_projects.data: summary.append(( 'Skipping existing project {0}.'.format(repo.name), False )) continue else: summary.append(( 'Project {0} updated.'.format(repo.name), True )) if options_form.set_hooks.data: # The user wanted us to auto-create web hooks for them. h = Hook.query.filter_by( project_id=p.id, service_id=10 ).first() if h is None: # No hooks for github have been setup yet, so go ahead # and create one. h = Hook.new(10) p.hooks.append(h) g.db.session.add(h) repo.create_hook('web', { 'url': url_for( 'projects.hook_receive', pid=p.id, key=h.key, _external=True ) }) if options_form.set_commits.data and p.public: # The user wanted us to add their public projects # to #[email protected] for them, but only if it # isn't already there. c = Channel.query.filter_by( host='irc.freenode.net', channel='#commits', project_id=p.id ).first() if c is None: # It does *not* already exist, so go ahead and add it. c = Channel.new( '#commits', 'irc.freenode.net', 6667, ssl=False, public=True ) p.channels.append(c) g.db.session.add(c) g.db.session.commit() return render_template('github.html', options_form=options_form, summary=summary, user_repos=admin_repos )
def github(): """ Import/merge the users existing Github projects, optionally setting up web hooks for them. """ if 'code' in request.args: # We've finished step one and have a temporary token. r = requests.post( 'https://github.com/login/oauth/access_token', params={ 'client_id': current_app.config['SERVICE_GITHUB_CLIENT_ID'], 'client_secret': current_app.config['SERVICE_GITHUB_CLIENT_SECRET'], 'code': request.args['code'] }, headers={'Accept': 'application/json'}) result = r.json() token = AuthToken.new(result['access_token'], 'github') db.session.add(token) g.user.tokens.append(token) db.session.commit() return redirect(url_for('.github')) # Check to see if the user has previously authenticated. access_token = AuthToken.query.filter_by(name='github', owner_id=g.user.id).first() if access_token is None: # The user hasn't setup Github yet, we need to get their OAuth # token. return redirect('https://github.com/login/oauth/authorize?{0}'.format( urllib.urlencode({ 'client_id': current_app.config['SERVICE_GITHUB_CLIENT_ID'], 'scope': 'repo' }))) # Set authentication and pull a JSON blob of all their # repos that they have actually created (or forked). # If we leave type as the default ("all") we also get # repos they have permission on, which we probably don't want. git = Github(access_token.token, user_agent="Notifico Github Import/0.1") # Test to make sure our token is still good... try: git.get_user().login except GithubException as exception: # Nope! if exception.status == 401: # The user almost certainly removed the OAuth token # from their github applications page. Remove the now-obsolete # token and refresh. access_token = AuthToken.query.filter_by( name='github', owner_id=g.user.id).first() if access_token: g.user.tokens.remove(access_token) db.session.delete(access_token) db.session.commit() return redirect(request.path) user = git.get_user() # Get all of the users own repositories user_repos = user.get_repos(type='all') # ... and get all of the repos in the users organizations ... all_repos = chain(user_repos, *[o.get_repos() for o in user.get_orgs()]) admin_repos = (r for r in all_repos if r.permissions.admin) summary = None options_form = GithubForm() if options_form.validate_on_submit(): summary = [] for repo in admin_repos: # User didn't check the box, don't import this project. # A hack-ish solution to wtform's BooleanField limitation, # or I would be using wtf.FieldList(wtf.BooleanField(...)). if request.form.get(str(repo.id), None) != 'y': continue # Make sure this project doesn't already exists. p = Project.by_name_and_owner(repo.name, g.user) if p is None: p = Project.new(repo.name, public=not repo.private, website=repo.homepage) p.full_name = '{0}/{1}'.format(g.user.username, p.name) g.user.projects.append(p) db.session.add(p) # We need to commit to generate the project.id which is # used for the following steps. db.session.commit() summary.append( ('Project {0} created.'.format(repo.name), True)) elif p is not None and not options_form.update_projects.data: summary.append( ('Skipping existing project {0}.'.format(repo.name), False)) continue else: summary.append( ('Project {0} updated.'.format(repo.name), True)) if options_form.set_hooks.data: # The user wanted us to auto-create web hooks for them. h = Hook.query.filter_by(project_id=p.id, service_id=10).first() if h is None: # No hooks for github have been setup yet, so go ahead # and create one. h = Hook.new(10) p.hooks.append(h) db.session.add(h) repo.create_hook( 'web', { 'url': url_for('projects.hook_receive', pid=p.id, key=h.key, _external=True) }) if options_form.set_commits.data and p.public: # The user wanted us to add their public projects # to #[email protected] for them, but only if it # isn't already there. c = Channel.query.filter_by(host='chat.freenode.net', channel='#commits', project_id=p.id).first() if c is None: # It does *not* already exist, so go ahead and add it. c = Channel.new('#commits', 'chat.freenode.net', 6667, ssl=False, public=True) p.channels.append(c) db.session.add(c) db.session.commit() return render_template('github.html', options_form=options_form, summary=summary, user_repos=admin_repos)