Add Github Navigator - Flask application

This commit is contained in:
Roman Mogylatov 2020-07-09 19:00:59 -04:00
parent 9afcd42633
commit e8e878e623
9 changed files with 191 additions and 0 deletions

View File

@ -0,0 +1,6 @@
github:
auth_token: ${GITHUB_TOKEN}
request_timeout: 10
search:
default_term: "Dependency Injector"
default_limit: 5

View File

@ -0,0 +1,32 @@
"""Application module."""
from dependency_injector import containers, providers
from . import github, views, webapp
class Application(containers.DeclarativeContainer):
"""Application container."""
config = providers.Configuration()
github_client = providers.Factory(
github.GitHubApiClient,
auth_token=config.github.auth_token,
request_timeout=config.github.request_timeout,
)
index_view = providers.Callable(
views.index,
github_client=github_client,
default_search_term=config.search.default_term,
default_search_limit=config.search.default_limit,
)
app = providers.Factory(
webapp.create_app,
name=__name__,
routes=[
webapp.Route('/', 'index', index_view, methods=['GET']),
],
)

View File

@ -0,0 +1,8 @@
"""Entrypoint module."""
from .application import Application
application = Application()
application.config.from_yaml('config.yml')
app = application.app()

View File

@ -0,0 +1,67 @@
"""Github API module."""
import requests
class GitHubApiClient:
"""GitHub API client performs operations with Github API."""
API_URL = 'https://api.github.com/'
DEFAULT_LIMIT = 5
def __init__(self, auth_token, request_timeout):
"""Initialize search."""
self._auth_token = auth_token
self._request_timeout = request_timeout
def search_repositories(self, search_term, limit):
"""Search repositories."""
if not search_term:
return []
repositories = self._make_search('repositories', search_term, limit)
latest_commits = [
self._get_latest_commit(repository, search_term)
for repository in repositories
]
return list(zip(repositories, latest_commits))
def _make_search(self, entity, search_term, limit):
headers = {}
if self._auth_token:
headers['authorization'] = f'token {self._auth_token}'
response = requests.get(
url=f'{self.API_URL}search/{entity}',
params={
'q': f'{search_term} in:name',
'sort': 'updated',
'order': 'desc',
'page': 1,
'per_page': limit,
},
headers=headers,
timeout=self._request_timeout,
)
data = response.json()
return data['items']
def _get_latest_commit(self, repository, search_term):
headers = {}
if self._auth_token:
headers['authorization'] = f'token {self._auth_token}'
response = requests.get(
url=repository['commits_url'].replace('{/sha}', ''),
params={
'q': f'{search_term} in:name',
'sort': 'updated',
'order': 'desc',
'page': 1,
'per_page': 1,
},
headers=headers,
timeout=self._request_timeout,
)
data = response.json()
return data[0]

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>Github Navigator</title>
</head>
<body>
<h1>Github Navigator</h1>
<form method="get">
<p>
Search term: <input type="text" name="search_term" value="{{ search_term if search_term }}">
Limit: <input type="text" name="limit" value="{{ limit }}">
<input type="submit">
</p>
</form>
<h2>Search results</h2>
{% if repositories|length == 0 %}
<small>No search results</small>
{% endif %}
{% for repository, latest_commit in repositories %} {{n}}
<p>
<small>Search result # {{ loop.index }} from {{ repositories|length }}</small>
</p>
<p>
Repository: <a href="{{ repository['html_url'] }}">{{ repository['name'] }}</a>
</p>
<p>
Repository owner:
<a href="{{ repository['owner']['html_url'] }}"><img src="{{ repository['owner']['avatar_url'] }}" alt="avatar" height="24" width="24"/></a>
<a href="{{ repository['owner']['html_url'] }}">{{ repository['owner']['login'] }}</a>
</p>
<p>
Created at: {{ repository['created_at'] }}
</p>
<p>
LastCommit: <a href="{{ latest_commit['html_url'] }}">{{ latest_commit['sha'] }}</a> {{ latest_commit['commit']['message'] }} {{ latest_commit['commit']['author']['name'] }}
</p>
<hr/>
{% endfor %}
</body>
</html>

View File

@ -0,0 +1,19 @@
"""Views module."""
from flask import request, render_template
from .github import GitHubApiClient
def index(github_client: GitHubApiClient, default_search_term, default_search_limit):
search_term = request.args.get('search_term', default_search_term)
limit = request.args.get('limit', default_search_limit)
repositories = github_client.search_repositories(search_term, limit)
return render_template(
'index.html',
search_term=search_term,
limit=limit,
repositories=repositories,
)

View File

@ -0,0 +1,16 @@
"""Web application module."""
from flask import Flask
def create_app(name, routes):
app = Flask(name)
for route in routes:
app.add_url_rule(*route.args, **route.kwargs)
return app
class Route:
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs

View File

@ -0,0 +1,3 @@
dependency-injector
flask
requests