def route(source_cls): """Registers browser extension URL routes for a given source class. ...specifically, with the source's short name as the routes' URL prefix. """ for route, cls in ( (f'/{source_cls.SHORT_NAME}/browser/status', Status), (f'/{source_cls.SHORT_NAME}/browser/homepage', Homepage), (f'/{source_cls.SHORT_NAME}/browser/profile', Profile), (f'/{source_cls.SHORT_NAME}/browser/feed', Feed), (f'/{source_cls.SHORT_NAME}/browser/post', Post), (f'/{source_cls.SHORT_NAME}/browser/likes', Reactions), (f'/{source_cls.SHORT_NAME}/browser/comments', Comments), (f'/{source_cls.SHORT_NAME}/browser/reactions', Reactions), (f'/{source_cls.SHORT_NAME}/browser/poll', Poll), (f'/{source_cls.SHORT_NAME}/browser/token-domains', TokenDomains), ): app.add_url_rule( route, view_func=cls.as_view(route), methods=['GET', 'POST'] if cls == Status else ['POST'])
return render_template('choose_blog.html', **vars) @app.route('/tumblr/add', methods=['POST']) def tumblr_add(): util.maybe_add_or_delete_source( Tumblr, ndb.Key(urlsafe=request.form['auth_entity_key']).get(), request.form['state'], blog_name=request.form['blog'], ) class SuperfeedrNotify(superfeedr.Notify): SOURCE_CLS = Tumblr # Tumblr doesn't seem to use scope # http://www.tumblr.com/docs/en/api/v2#oauth start = util.oauth_starter(oauth_tumblr.Start).as_view('tumblr_start', '/tumblr/choose_blog') app.add_url_rule('/tumblr/start', view_func=start, methods=['POST']) app.add_url_rule('/tumblr/choose_blog', view_func=ChooseBlog.as_view('tumblr_choose_blog', 'unused')) app.add_url_rule('/tumblr/delete/finish', view_func=oauth_tumblr.Callback.as_view( 'tumblr_delete_finish', '/delete/finish')) app.add_url_rule('/tumblr/notify/<id>', view_func=SuperfeedrNotify.as_view('tumblr_notify'), methods=['POST'])
"""Custom handler to add Flickr source when auth completes. If this account was previously authorized with greater permissions, this will trigger another round of auth with elevated permissions. """ def finish(self, auth_entity, state=None): logger.debug(f'finish with {auth_entity}, {state}') source = util.maybe_add_or_delete_source(Flickr, auth_entity, state) feature = util.decode_oauth_state(state).get('feature') if source and feature == 'listen' and 'publish' in source.features: # we had signed up previously with publish, so we'll reauth to # avoid losing that permission logger.info('Restarting OAuth flow to get publish permissions.') source.features.remove('publish') source.put() return self.start_oauth_flow('publish') app.add_url_rule('/flickr/start', view_func=Start.as_view('flickr_start', '/flickr/add'), methods=['POST']) app.add_url_rule('/flickr/add', view_func=AddFlickr.as_view('flickr_add', 'unused')) app.add_url_rule('/flickr/delete/finish', view_func=oauth_flickr.Callback.as_view( 'flickr_delete_finish', '/delete/finish')) app.add_url_rule('/flickr/publish/start', view_func=oauth_flickr.Start.as_view( 'flickr_publish_start', '/publish/flickr/finish'), methods=['POST'])
self.entity.type = 'rsvp' if not text: content['value'] = f'RSVPed {rsvp}.' else: self.entity.type = {'in-reply-to': 'comment', 'like-of': 'like', 'repost-of': 'repost', }.get(type, type) if not text: content['value'] = {'comment': 'replied to this.', 'like': 'liked this.', 'repost': 'reposted this.', }[self.entity.type] return item # check children in case this is eg an h-feed found = self.find_mention_item(item.get('children', [])) if found: return found return None def any_target_in(self, haystack): """Returns true if any target URL (including redirects) is in haystack.""" return any(url in haystack for url in self.entity.redirected_target_urls + [self.target_url]) app.add_url_rule('/webmention/<any(blogger,fake,tumblr,wordpress):site>', view_func=BlogWebmentionView.as_view('blog_wm'), methods=['POST'])
self.merge_urls(repost, 'object', originals) return repost class Rsvp(Item): def get_item(self, event_id, user_id): event = self.source.gr_source.get_event(event_id) rsvp = self.source.gr_source.get_rsvp(self.source.key_id(), event_id, user_id, event=event) if event: originals, mentions = original_post_discovery.discover( self.source, event, fetch_hfeed=False) self.merge_urls(rsvp, 'inReplyTo', originals) return rsvp app.add_url_rule('/post/<site>/<key_id>/<post_id>', view_func=Post.as_view('post')) app.add_url_rule('/comment/<site>/<key_id>/<post_id>/<comment_id>', view_func=Comment.as_view('comment')) app.add_url_rule('/like/<site>/<key_id>/<post_id>/<user_id>', view_func=Like.as_view('like')) app.add_url_rule('/react/<site>/<key_id>/<post_id>/<user_id>/<reaction_id>', view_func=Reaction.as_view('react')) app.add_url_rule('/repost/<site>/<key_id>/<post_id>/<share_id>', view_func=Repost.as_view('repost')) app.add_url_rule('/rsvp/<site>/<key_id>/<event_id>/<user_id>', view_func=Rsvp.as_view('rsvp'))
class Start(View): def dispatch_request(self): features = request.form['feature'] scopes = PUBLISH_SCOPES if 'publish' in features else LISTEN_SCOPES starter = util.oauth_starter(oauth_github.Start, feature=features)('/github/add', scopes=scopes) return starter.dispatch_request() class AddGitHub(oauth_github.Callback): def finish(self, auth_entity, state=None): logger.debug(f'finish with {auth_entity}, {state}') util.maybe_add_or_delete_source(GitHub, auth_entity, state) app.add_url_rule('/github/start', view_func=Start.as_view('github_start'), methods=['POST']) app.add_url_rule('/github/add', view_func=AddGitHub.as_view('github_add', 'unused')) app.add_url_rule('/github/delete/finish', view_func=oauth_github.Callback.as_view( 'github_delete_finish', '/delete/finish')) app.add_url_rule('/github/publish/start', view_func=oauth_github.Start.as_view('github_publish_start', '/publish/github/finish', scopes=PUBLISH_SCOPES), methods=['POST'])
class Callback(indieauth.Callback): """IndieAuth callback handler.""" def finish(self, auth_entity, state=None): if not auth_entity: return assert state @ndb.transactional() def add_or_update_domain(): domain = Domain.get_or_insert( util.domain_from_link( util.replace_test_domains_with_localhost( auth_entity.key.id()))) domain.auth = auth_entity.key if state not in domain.tokens: domain.tokens.append(state) domain.put() flash(f'Authorized you for {domain.key.id()}.') add_or_update_domain() return redirect('/') app.add_url_rule('/indieauth/start', view_func=Start.as_view('indieauth_start', '/indieauth/callback'), methods=['POST']) app.add_url_rule('/indieauth/callback', view_func=Callback.as_view('indieauth_callback', 'unused'))
current_image_size=current_image_size, current_version=current_version) def post(self): """ Receive the image file and save it in temporary folder :return: web-page for successful image sending """ if 'image' not in request.files: return "No file sent!" file = request.files['image'] self.image_file = secure_filename(file.filename) os.makedirs(self.image_path, exist_ok=True) file.save(os.path.join(self.image_path, self.image_file)) self.notify() return "Update image sent!" def get(self): return self.poll() # NOTE: Tried to use a blueprint here, doesn't work for some reason app.add_url_rule("/update/", view_func=WebInput.as_view("web_input")) app.add_url_rule("/update/send_image/", view_func=WebInput.as_view("send_image"))
if self.entity.html: for url in expected: if url in self.entity.html or urllib.parse.quote( url, safe='') in self.entity.html: return True self.error(f"Couldn't find link to {expected[0]}") return False def error(self, error, **kwargs): logging.info(f'publish: {error}') return super().error(error, **kwargs) app.add_url_rule('/publish/preview', view_func=Preview.as_view('publish_preview'), methods=['POST']) app.add_url_rule('/publish/webmention', view_func=Webmention.as_view('publish_webmention'), methods=['POST']) app.add_url_rule('/publish/flickr/finish', view_func=FlickrSend.as_view('publish_flickr_finish', 'unused')) app.add_url_rule('/publish/github/finish', view_func=GitHubSend.as_view('publish_github_finish', 'unused')) app.add_url_rule('/publish/mastodon/finish', view_func=MastodonSend.as_view('publish_mastodon_finish', 'unused')) app.add_url_rule('/publish/twitter/finish', view_func=TwitterSend.as_view('publish_twitter_finish',
raise models.DisableSource() def search_for_links(self): """Searches for activities with links to any of this source's web sites. Returns: sequence of ActivityStreams activity dicts """ urls = {util.schemeless(util.fragmentless(url), slashes=False) for url in self.domain_urls if not util.in_webmention_blocklist(util.domain_from_link(url))} if not urls: return [] # Search syntax: https://www.reddit.com/wiki/search url_query = ' OR '.join(f'site:"{u}" OR selftext:"{u}"' for u in urls) return self.get_activities( search_query=url_query, group_id=gr_source.SEARCH, etag=self.last_activities_etag, fetch_replies=False, fetch_likes=False, fetch_shares=False, count=50) class Callback(oauth_reddit.Callback): def finish(self, auth_entity, state=None): util.maybe_add_or_delete_source(Reddit, auth_entity, state) app.add_url_rule('/reddit/start', view_func=util.oauth_starter(oauth_reddit.Start).as_view('reddit_start', '/reddit/callback'), methods=['POST']) app.add_url_rule('/reddit/callback', view_func=Callback.as_view('reddit_callback', 'unused to_path'))
redirect(request.path) class Callback(oauth_dropins.mastodon.Callback): def finish(self, auth_entity, state=None): source = util.maybe_add_or_delete_source(Mastodon, auth_entity, state) features = util.decode_oauth_state(state).get('feature', '').split(',') if set(features) != set(source.features): # override features with whatever we requested scopes for just now, since # scopes are per access token. background: # https://github.com/snarfed/bridgy/issues/1015 source.features = features source.put() app.add_url_rule('/mastodon/start', view_func=Start.as_view('mastodon_start', '/mastodon/callback'), methods=['POST']) app.add_url_rule('/mastodon/callback', view_func=Callback.as_view('mastodon_callback', 'unused')) app.add_url_rule('/mastodon/delete/finish', view_func=oauth_dropins.mastodon.Callback.as_view( 'mastodon_delete_finish', '/delete/finish')) app.add_url_rule('/mastodon/publish/start', view_func=StartBase.as_view('mastodon_publish_finish', '/publish/mastodon/finish', scopes=PUBLISH_SCOPES), methods=['POST'])
'title': p.get('name', ''), 'url': p.get('url', ''), 'pretty_url': util.pretty_link(str(p.get('url', ''))), 'image': p.get('imageUrl', ''), } for p in pubs if p.get('id')], } logger.info(f'Rendering choose_blog.html with {vars}') return render_template('choose_blog.html', **vars) class SuperfeedrNotify(superfeedr.Notify): SOURCE_CLS = Medium # https://github.com/Medium/medium-api-docs#user-content-21-browser-based-authentication start = util.oauth_starter(oauth_medium.Start).as_view( 'medium_start', '/medium/choose_blog', scopes=('basicProfile', 'listPublications')) app.add_url_rule('/medium/start', view_func=start, methods=['POST']) app.add_url_rule('/medium/choose_blog', view_func=ChooseBlog.as_view('medium_choose_blog', 'unused to_path'), methods=['GET']) app.add_url_rule('/medium/delete/finish', view_func=oauth_medium.Callback.as_view( 'medium_delete', '/delete/finish')), app.add_url_rule('/medium/notify/<id>', view_func=SuperfeedrNotify.as_view('medium_notify'), methods=['POST'])
# -*- coding: utf-8 -*- from flask_app import app from controllers import * app.error_handlers[500] = error_controller.exception app.error_handlers[404] = error_controller.not_found app.add_url_rule('/sitemap.xml', view_func = robot_controller.sitemap) app.add_url_rule('/robots.txt', view_func = robot_controller.robots) # Board app.add_url_rule('/', 'board.view', view_func = board_controller.view) app.add_url_rule('/om', 'board.about', view_func = board_controller.about) app.add_url_rule('/admin', 'board.control_panel', view_func = board_controller.control_panel) # Job app.add_url_rule('/stilling/<int:id>/', 'job.view', view_func = job_controller.view) app.add_url_rule('/stilling/<int:id>/<string:token>', 'job.preview', view_func = job_controller.preview) app.add_url_rule('/admin/stilling/', 'job.new', view_func = job_controller.new) app.add_url_rule('/admin/stilling/<int:id>/', 'job.edit', view_func = job_controller.edit) app.add_url_rule('/admin/stilling/', 'job.create', view_func = job_controller.create, methods = ['POST']) app.add_url_rule('/admin/stilling/<int:id>/', 'job.update', view_func = job_controller.update, methods = ['POST']) # Scraped job app.add_url_rule('/admin/skrapt/<string:guid>/', 'scraped_job.edit', view_func = scraped_job_controller.edit) app.add_url_rule('/admin/skrapt/<string:guid>/delete', 'scraped_job.delete', view_func = scraped_job_controller.delete, methods = ['GET']) # Company app.add_url_rule('/admin/selskap/', 'comapany.new', view_func = company_controller.new) app.add_url_rule('/admin/selskap/list', 'company.list', view_func = company_controller.list) app.add_url_rule('/admin/selskap/<int:id>/', 'company.edit', view_func = company_controller.edit) app.add_url_rule('/admin/selskap/', 'company.create', view_func = company_controller.create, methods = ['POST'])
@app.route('/blogger/add', methods=['POST']) def blogger_add(): util.maybe_add_or_delete_source( Blogger, ndb.Key(urlsafe=request.form['auth_entity_key']).get(), request.form['state'], blog_id=request.form['blog'], ) class SuperfeedrNotify(superfeedr.Notify): SOURCE_CLS = Blogger # Blogger only has one OAuth scope. oauth-dropins fills it in. # https://developers.google.com/blogger/docs/2.0/developers_guide_protocol#OAuth2Authorizing start = util.oauth_starter(oauth_blogger.Start).as_view( 'blogger_start', '/blogger/oauth2callback') app.add_url_rule('/blogger/start', view_func=start, methods=['POST']) app.add_url_rule('/blogger/oauth2callback', view_func=oauth_blogger.Callback.as_view( 'blogger_oauth2callback', '/blogger/oauth_handler')) app.add_url_rule('/blogger/delete/start', view_func=oauth_blogger.Start.as_view( 'blogger_delete_start', '/blogger/oauth2callback')) app.add_url_rule('/blogger/notify/<id>', view_func=SuperfeedrNotify.as_view('blogger_notify'), methods=['POST'])
if site_info is None: return elif site_info.get('jetpack'): logger.info(f'This is a self-hosted WordPress blog! {auth_entity.key_id()} {auth_entity.blog_id}') return render_template('confirm_self_hosted_wordpress.html', auth_entity_key=auth_entity.key.urlsafe().decode(), state=state) util.maybe_add_or_delete_source(WordPress, auth_entity, state) @app.route('/wordpress/confirm', methods=['POST']) def confirm_self_hosted(): util.maybe_add_or_delete_source( WordPress, ndb.Key(urlsafe=request.form['auth_entity_key']).get(), request.form['state']) class SuperfeedrNotify(superfeedr.Notify): SOURCE_CLS = WordPress # wordpress.com doesn't seem to use scope # https://developer.wordpress.com/docs/oauth2/ start = util.oauth_starter(oauth_wordpress.Start).as_view( 'wordpress_start', '/wordpress/add') app.add_url_rule('/wordpress/start', view_func=start, methods=['POST']) app.add_url_rule('/wordpress/add', view_func=Add.as_view('wordpress_add', 'unused')) app.add_url_rule('/wordpress/notify/<id>', view_func=SuperfeedrNotify.as_view('wordpress_notify'), methods=['POST'])