Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for url prefixes #109

Merged
merged 4 commits into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions conda-store-server/conda_store_server/server/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging

from flask import Flask
from flask.blueprints import Blueprint
from flask_cors import CORS
from traitlets import Bool, Unicode, Integer, Type
from traitlets.config import Application
Expand Down Expand Up @@ -44,6 +45,14 @@ class CondaStoreServer(Application):

port = Integer(5000, help="port for conda-store server", config=True)

url_prefix = Unicode(
"/",
help="the prefix URL (subdirectory) for the entire application; "
"it MUST start with a forward slash - tip: "
"use this to run conda-store within an existing website.",
config=True,
)

config_file = Unicode(
"conda_store_config.py", help="config file to load for conda-store", config=True
)
Expand Down Expand Up @@ -71,16 +80,16 @@ def start(self):
app.secret_key = self.secret_key
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This route also needs to account for the url_prefix.


if self.enable_api:
app.register_blueprint(views.app_api)
app.register_blueprint(views.app_api, url_prefix=self.url_prefix)

if self.enable_registry:
app.register_blueprint(views.app_registry)
app.register_blueprint(views.app_registry, url_prefix=self.url_prefix)

if self.enable_ui:
app.register_blueprint(views.app_ui)
app.register_blueprint(views.app_ui, url_prefix=self.url_prefix)

if self.enable_metrics:
app.register_blueprint(views.app_metrics)
app.register_blueprint(views.app_metrics, url_prefix=self.url_prefix)

app.conda_store = CondaStore(parent=self, log=self.log)
app.authentication = self.authentication_class(parent=self, log=self.log)
Expand All @@ -93,8 +102,16 @@ def after_request_function(response):
return response

# add dynamic routes
# NOTE: this will break`url_for`, since the method names behind each
# route are not standardized; we build them "manually" by using `url_for`
# pointing to the "/" (index) provider (right now is ui.ui_list_environments)
# If the index function changes names, this will HAVE to be updated manually
# on some templates too.

app_auth = Blueprint("auth", self.authentication_class.__name__)
for route, method, func in app.authentication.routes:
app.add_url_rule(route, func.__name__, func, methods=[method])
app_auth.add_url_rule(route, func.__name__, func, methods=[method])
app.register_blueprint(app_auth, url_prefix=self.url_prefix)

app.conda_store.ensure_namespace()
app.conda_store.ensure_directories()
Expand Down
2 changes: 1 addition & 1 deletion conda-store-server/conda_store_server/server/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ def get_login_html(self):
authorization_url = self.oauth_route(
auth_url=self.authorize_url,
client_id=self.client_id,
redirect_uri=url_for("post_login_method", _external=True),
redirect_uri=url_for("auth.post_login_method", _external=True),
scope=self.access_scope,
state=state,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,17 @@ <h3 class="card-title">Conda Packages
<h3 class="card-title">Conda Environment Artifacts</h3>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">YAML: <a href="/build/{{ build.id }}/yaml/">environment.yaml</a></li>
<li class="list-group-item">Lockfile: <a href="/build/{{ build.id }}/lockfile/">conda-{{ platform }}.lock</a></li>
<li class="list-group-item">Archive: <a href="/build/{{ build.id }}/archive/">environment.tar.gz</a></li>
<li class="list-group-item">YAML: <a href="{{ url_for('ui.api_get_build_yaml', build_id=build.id) }}">environment.yaml</a></li>
<li class="list-group-item">Lockfile: <a href="{{ url_for('ui.api_get_build_lockfile', build_id=build.id) }}">conda-{{ platform }}.lock</a></li>
<li class="list-group-item">Archive: <a href="{{ url_for('ui.api_get_build_archive', build_id=build.id) }}">environment.tar.gz</a></li>
</ul>
</div>
{% endif %}

{% if build.status.value in ['COMPLETED', 'FAILED'] %}
<div class="card my-2">
<div class="card-body">
<a href="/build/{{ build.id }}/logs/" class="btn btn-primary btn-block">Full Logs</a>
<a href="{{ url_for('ui.api_get_build_logs', build_id=build.id) }}" class="btn btn-primary btn-block">Full Logs</a>
</div>
</div>
{% endif %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<pre class="alert alert-danger" role="alert">{{ message }}</pre>
{% endif %}

<form action="/create/" method="post">
<form action="{{ url_for('ui.ui_create_get_environment') }}" method="post">
<div>
<label for="namespace">Namespace</label>
<select class="form-select" name="namespace" id="namespace" aria-label="namespace">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ <h5 class="card-title">{{ environment.namespace.name }}/{{ environment.name }}
</li>
</ul>
<div class="card-body">
<a href="/environment/{{ environment.namespace.name }}/{{ environment.name }}/edit/" class="btn btn-primary btn-block">Edit</a>
<a href="{{ url_for('ui.ui_edit_environment', namespace=environment.namespace.name, name=environment.name) }}" class="btn btn-primary btn-block">Edit</a>
</div>
</div>

<h3>Builds</h3>
<ul class="list-group">
{% for build in environment_builds %}
<li class="list-group-item d-flex justify-content-between align-items-center {% if build.id == environment.build_id %}list-group-item-success{% elif build.deleted_on is not none %}list-group-item-secondary{% endif %}">
<a href="/build/{{ build.id }}/">Build {{ build.id }}</a>
<a href="{{ url_for('ui.ui_get_build', build_id=build.id) }}/">Build {{ build.id }}</a>
<span>{{ build.status.value }}</span>
<div class="btn-group" role="group" aria-label="Build actions">
{% if build.id != environment.build_id and build.status.value == 'COMPLETED' and build.deleted_on is none %}
Expand Down Expand Up @@ -56,7 +56,7 @@ <h3>Builds</h3>
editor.setReadOnly(true);

function updateEnvironmentBuild(buildId) {
fetch(`/api/v1/environment/{{ environment.namespace.name }}/{{ environment.name }}/`, {
fetch(`{{ url_for('api.api_get_environment', namespace=environment.namespace.name, name=environment.name) }}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Expand All @@ -66,7 +66,7 @@ <h3>Builds</h3>
}

function buildAction(method, buildId) {
fetch(`/api/v1/build/${buildId}/`, {
fetch(`{{ url_for('api.api_list_builds') }}${buildId}/`, {
method: method,
}).then(response => window.location.reload(true));
}
Expand Down
10 changes: 5 additions & 5 deletions conda-store-server/conda_store_server/server/templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ <h2>Environments</h2>
<div class="card my-2">
<div class="card-body">
<h5 class="card-title">
<a href="/environment/{{environment.namespace.name }}/{{ environment.name }}/">{{ environment.namespace.name }}/{{ environment.name }}</a>
<a href="{{ url_for('ui.ui_get_environment', namespace=environment.namespace.name, name=environment.name) }}">{{ environment.namespace.name }}/{{ environment.name }}</a>
<span class="badge badge-light">{{ (environment.build.size or 0) | filesizeformat(true) }}</span>
</h5>
{% if environment.build.status.value == 'COMPLETED' %}
<a class="card-link" href="/build/{{ environment.build_id }}/yaml/"><ion-icon name="code-download"></ion-icon> YAML</a>
<a class="card-link" href="/build/{{ environment.build_id }}/lockfile/"><ion-icon name="lock-closed-outline"></ion-icon> Lockfile</a>
<a class="card-link" href="/build/{{ environment.build_id }}/archive/"><ion-icon name="archive-outline"></ion-icon> Archive</a>
<a class="card-link" onclick="setClipboard('localhost:5000/{{ environment.namespace }}/{{ environment.name }}:{{ environment.build.specification.sha256 }}')"><ion-icon name="logo-docker"></ion-icon> Docker</a>
<a class="card-link" href="{{ url_for('ui.api_get_build_yaml', build_id=environment.build_id) }}"><ion-icon name="code-download"></ion-icon> YAML</a>
<a class="card-link" href="{{ url_for('ui.api_get_build_lockfile', build_id=environment.build_id) }}"><ion-icon name="lock-closed-outline"></ion-icon> Lockfile</a>
<a class="card-link" href="{{ url_for('ui.api_get_build_archive', build_id=environment.build_id) }}"><ion-icon name="archive-outline"></ion-icon> Archive</a>
<a class="card-link" onclick="setClipboard('{{ url_for('ui.ui_list_environments', _external=True) }}{{ environment.namespace }}/{{ environment.name }}:{{ environment.build.specification.sha256 }}')"><ion-icon name="logo-docker"></ion-icon> Docker</a>
{% endif %}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-2" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/">Conda-Store</a>
<a class="navbar-brand" href="{{ url_for('ui.ui_list_environments') }}">Conda-Store</a>
</div>

<div class="nav navbar-right">
<ul class="nav navbar-nav">
{% if entity is none %}
<li>
<a class="btn btn-outline-success my-2 my-sm-0 mr-2" href="/login/" role="button">
<a class="btn btn-outline-success my-2 my-sm-0 mr-2" href="{{ url_for('ui.ui_list_environments') }}login" role="button">
Login
</a>
</li>
{% else %}
<li>
<a class="btn btn-outline-success my-2 my-sm-0 mr-2" href="/user/" role="button">
<a class="btn btn-outline-success my-2 my-sm-0 mr-2" href="{{ url_for('ui.ui_get_user') }}" role="button">
User
</a>
</li>
{% endif %}
<li>
<a class="btn btn-outline-success my-2 my-sm-0 mr-2" href="/create/" role="button">
<a class="btn btn-outline-success my-2 my-sm-0 mr-2" href="{{ url_for('ui.ui_create_get_environment') }}" role="button">
Create Environment
</a>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ <h1 class="h3 mb-3 fw-normal">Logged in as {{ username }}</h1>
{% if email is defined %}
<p><em>Email:</em> {{ email }}</p>
{% endif %}
<form action="/logout/" method="POST">
<form action="{{ url_for('ui.ui_list_environments') }}logout/" method="POST">
<button type="submit" class="btn btn-outline-success my-2 my-sm-0 mr-2">Logout</button>
</form>
</div>
Expand Down
5 changes: 3 additions & 2 deletions conda-store-server/conda_store_server/server/views/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
request,
redirect,
Response,
url_for,
)
import pydantic
import yaml
Expand Down Expand Up @@ -39,7 +40,7 @@ def ui_create_get_environment():
)
namespace = api.get_namespace(conda_store.db, id=namespace_id)
api.post_specification(conda_store, specification.dict(), namespace.name)
return redirect("/")
return redirect(url_for("ui.ui_list_environments"))
except yaml.YAMLError:
return render_template(
"create.html",
Expand Down Expand Up @@ -165,7 +166,7 @@ def ui_get_user():

entity = auth.authenticate_request()
if entity is None:
return redirect("/login/")
return redirect(f"{url_for('ui.ui_list_environments')}login/")

context = {"username": entity.primary_namespace}
return render_template("user.html", **context)
Expand Down
2 changes: 2 additions & 0 deletions tests/assets/conda_store_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
c.CondaStoreServer.enable_metrics = True
c.CondaStoreServer.address = "0.0.0.0"
c.CondaStoreServer.port = 5000
# This MUST start with `/`
c.CondaStoreServer.url_prefix = "/conda-store"


# ==================================
Expand Down
2 changes: 1 addition & 1 deletion tests/assets/jupyterhub_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
'oauth_client_id': "service-this-is-a-jupyterhub-client",
'admin': True,
'api_token': "this-is-a-jupyterhub-secret",
'oauth_redirect_uri': 'http://localhost:5000/oauth_callback/',
'oauth_redirect_uri': 'http://localhost:5000/conda-store/oauth_callback/',
}
]