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 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 new_channel(u, p): 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 = ChannelDetailsForm() if form.validate_on_submit(): host = form.host.data.strip().lower() channel = form.channel.data.strip().lower() # Make sure this isn't a duplicate channel before we create it. c = Channel.query.filter_by(host=host, channel=channel, project_id=p.id).first() if not c: c = Channel.new(channel, host, port=form.port.data, ssl=form.ssl.data, public=form.public.data) p.channels.append(c) db.session.add(c) db.session.commit() return redirect(url_for('.details', p=p.name, u=u.username)) else: form.channel.errors = [ wtf.ValidationError( 'You cannot have a project in the same channel twice.') ] return render_template('new_channel.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() 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 network(network): per_page = min(int(request.args.get('l', 25)), 100) page = max(int(request.args.get('page', 1)), 1) q = Channel.visible(Channel.query.filter(Channel.host == network), user=g.user).order_by(Channel.created.desc()) pagination = q.paginate(page, per_page, False) return render_template('channels.html', per_page=per_page, network=network, pagination=pagination)
def network(network): per_page = min(int(request.args.get('l', 25)), 100) page = max(int(request.args.get('page', 1)), 1) q = Channel.visible( Channel.query.filter(Channel.host == network), user=g.user ).order_by(Channel.created.desc()) pagination = q.paginate(page, per_page, False) return render_template('channels.html', per_page=per_page, network=network, pagination=pagination )
def networks(): per_page = min(int(request.args.get('l', 25)), 100) page = max(int(request.args.get('page', 1)), 1) q = (Channel.visible(db.session.query( Channel.host, func.count(func.distinct(Channel.channel)).label('di_count'), func.count(Channel.channel).label('count')), user=g.user).group_by( Channel.host).order_by('di_count desc')) total = q.count() items = q.limit(per_page).offset((page - 1) * per_page).all() pagination = Pagination(q, page, per_page, total, items) return render_template('networks.html', pagination=pagination, per_page=per_page)
def networks(): per_page = min(int(request.args.get('l', 25)), 100) page = max(int(request.args.get('page', 1)), 1) q = ( Channel.visible(g.db.session.query( Channel.host, func.count(func.distinct(Channel.channel)).label('di_count'), func.count(Channel.channel).label('count') ), user=g.user) .group_by(Channel.host) .order_by('di_count desc') ) total = q.count() items = q.limit(per_page).offset((page - 1) * per_page).all() pagination = Pagination(q, page, per_page, total, items) return render_template('networks.html', pagination=pagination, per_page=per_page )
def new_channel(u, p): 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 = ChannelDetailsForm() if form.validate_on_submit(): host = form.host.data.strip().lower() channel = form.channel.data.strip().lower() # Make sure this isn't a duplicate channel before we create it. c = Channel.query.filter_by( host=host, channel=channel, project_id=p.id ).first() if not c: c = Channel.new( channel, host, port=form.port.data, ssl=form.ssl.data, public=form.public.data ) p.channels.append(c) g.db.session.add(c) g.db.session.commit() flash('Your channel has been created.', 'success') return redirect(url_for('.details', p=p.name, u=u.username)) else: form.channel.errors = [wtf.ValidationError( 'You cannot have a project in the same channel twice.' )] return render_template('new_channel.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 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)
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 )