* Add machinery for enabling app transfer

* fix scripts

* use defer instead of async

* add changelog entry

* add alert if user has no apps to transfer

* wording fixes

* wording

* wording

* make urls consistent

* add badge for npm requirements
This commit is contained in:
Bernhard Posselt 2017-03-26 11:43:54 +02:00 коммит произвёл GitHub
Родитель d00cb2db33
Коммит 6dcf34417e
16 изменённых файлов: 105 добавлений и 16 удалений

Просмотреть файл

@ -17,6 +17,7 @@ Unreleased
- Added support to switch between language comments
- Added support to easily post ratings in multiple languages
- Added support for running New Relic on servers
- Added ability to transfer app ownership
**Fixed**

Просмотреть файл

@ -11,6 +11,9 @@ Nextcloud App Store
.. image:: https://requires.io/github/nextcloud/appstore/requirements.svg?branch=master
:target: https://requires.io/github/nextcloud/appstore/requirements/?branch=master
:alt: Requirements Status
.. image:: https://david-dm.org/nextcloud/appstore.svg
:target: https://github.com/nextcloud/appstore/blob/master/package.json
:alt: Package.json Status
.. image:: https://img.shields.io/badge/license-AGPLv3+-blue.svg
:target: https://www.gnu.org/licenses/agpl-3.0.en.html
:alt: License
@ -18,6 +21,7 @@ Nextcloud App Store
:target: https://webchat.freenode.net/?channels=nextcloud-dev
:alt: IRC
A new app store for Nextcloud apps built with Django.
Documentation including Setup and API Specification are `available on Read the Docs <https://nextcloudappstore.readthedocs.io/en/latest/>`_

Просмотреть файл

@ -72,6 +72,9 @@ After we approved your certificate, we will post your signed public certificate
.. note:: Be sure to follow the directory and naming structure for certificates. All our documentation examples and tools will assert this structure.
.. _app-register:
Registering an App
~~~~~~~~~~~~~~~~~~
After you've obtained your signed public certificate you can use it to register your app id on the App Store. To do that either use the :ref:`REST API <api-register-app>` or use the App Store's `register app web interface <https://apps.nextcloud.com/developer/apps/new>`_.
@ -115,6 +118,8 @@ We then download the archive and verify the signature. In addition we try to ver
If everything went well the release is then either created or updated. The downloaded archive will be deleted from our server.
.. _app-revoke-cert:
Revoking a Certificate
~~~~~~~~~~~~~~~~~~~~~~
If you've lost or leaked your private certificate you want to revoke your certificate.
@ -123,6 +128,16 @@ You can revoke your previous certificate by either posting your public certifica
After you've obtained a new certificate, simply use it to register your app id again (only owners are allowed to do this). This will delete all previous releases from our server since their signature has become invalid.
Transferring Your App to a New Owner
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Transferring an app works similar to :ref:`registering an app <app-register>`: The new owner simply needs to register the app again using the public certificate and the signature.
However by default this is restricted to the app's owner. To disable this restriction you first need to unlock your app for the owner transfer. You can do this by going to your **account** settings and choosing `Transfer app ownership <https://apps.nextcloud.com/account/transfer-apps>`_. On that page you can lock or unlock your apps for being transferred.
After you unlocked your app for transfer, the new owner can then proceed to register the app again. If everything went fine the app is now transferred to the new owner and the transfer setting for that app is locked again.
.. _app-metadata:
App Metadata

Просмотреть файл

@ -45,9 +45,10 @@ class CategoryAdmin(TranslatableAdmin):
@admin.register(App)
class AppAdmin(TranslatableAdmin):
list_display = ('id', 'owner', 'name', 'last_release', 'rating_recent',
'rating_overall', 'summary', 'ocsid', 'is_featured')
'rating_overall', 'summary', 'ocsid', 'is_featured',
'ownership_transfer_enabled')
list_filter = ('owner', 'co_maintainers', 'categories', 'created',
'is_featured', 'last_release')
'is_featured', 'last_release', 'ownership_transfer_enabled')
ordering = ('id',)

Просмотреть файл

@ -1,6 +1,5 @@
import os
from itertools import chain
from typing import List, Callable
"""
Contains small utility and shortcut functions

Просмотреть файл

@ -5,7 +5,7 @@
{% block head %}
<link rel="stylesheet" href="{% static 'assets/css/img-slider.css' %}">
<link rel="stylesheet" href="{% static 'vendor/github.css' %}">
<script async src="{% static 'public/app/detail.js' %}"></script>
<script defer src="{% static 'public/app/detail.js' %}"></script>
<meta name="description-url" content="{% url 'app-description' object.id %}">
<meta name="ratings-url" content="{% url 'app-ratings' object.id %}">
<meta name="language-code" content="{{ request.LANGUAGE_CODE }}">

Просмотреть файл

@ -4,7 +4,7 @@
{% block head-title %}{% if current_category %}{{ current_category.name }} - {% else %}{% trans 'All apps' %} - {% endif %}{% endblock %}
{% block head %}
<script async src="{% static 'public/app/list.js' %}"></script>
<script defer src="{% static 'public/app/list.js' %}"></script>
{% endblock %}
{% block apps %}

Просмотреть файл

@ -5,7 +5,7 @@
{% block head-title %}{% trans 'Register app' %} - {% endblock %}
{% block head %}
<script async src="{% static 'public/app/register.js' %}"></script>
<script defer src="{% static 'public/app/register.js' %}"></script>
{% endblock %}
{% block content %}

Просмотреть файл

@ -5,7 +5,7 @@
{% block head %}
<link rel="stylesheet" href="{% static 'assets/css/accordion.css' %}">
<script async src="{% static 'public/app/releases.js' %}"></script>
<script defer src="{% static 'public/app/releases.js' %}"></script>
{% endblock %}
{% block apps %}

Просмотреть файл

@ -5,7 +5,7 @@
{% block head-title %}{% trans 'Upload app release' %} - {% endblock %}
{% block head %}
<script async src="{% static 'public/app/upload.js' %}"></script>
<script defer src="{% static 'public/app/upload.js' %}"></script>
{% endblock %}
{% block content %}

Просмотреть файл

@ -16,11 +16,9 @@
<link rel="stylesheet" href="{% static 'assets/css/theme.css' %}">
<link rel="alternate" type="application/atom+xml" title="News" href="{% url 'feeds-releases-atom' %}" />
<link rel="alternate" type="application/rss+xml" title="News" href="{% url 'feeds-releases-rss' %}" />
<script src="{% static 'vendor/jquery/dist/jquery.min.js' %}" async></script>
<script src="{% static 'vendor/fetch/fetch.js' %}" async></script>
<!-- used to migrate js code from previous to new model -->
<script
src="{% static 'vendor/bootstrap/dist/js/bootstrap.min.js' %}" async></script>
<script src="{% static 'vendor/fetch/fetch.js' %}" defer></script>
<script src="{% static 'vendor/jquery/dist/jquery.min.js' %}" defer></script>
<script src="{% static 'vendor/bootstrap/dist/js/bootstrap.min.js' %}" defer></script>
{% block head %}{% endblock %}
</head>

Просмотреть файл

@ -3,7 +3,7 @@
{% load staticfiles %}
{% block head %}
<script async src="{% static 'public/user/token.js' %}"></script>
<script defer src="{% static 'public/user/token.js' %}"></script>
{% endblock %}
{% block head-title %}{% trans 'API Token' %} - {% endblock %}

Просмотреть файл

@ -11,6 +11,9 @@
<li class="{% if acc_page == 'account' %}active{% endif %}">
<a href="{% url 'user:account' %}">{% trans 'Account' %}</a>
</li>
<li class="{% if acc_page == 'account-transfer-apps' %}active{% endif %}">
<a href="{% url 'user:account-transfer-apps' %}">{% trans 'Transfer app ownership' %}</a>
</li>
<li class="{% if acc_page == 'account-change-language' %}active{% endif %}">
<a href="{% url 'user:account-change-language' %}">{% trans 'Change language' %}</a>
</li>

Просмотреть файл

@ -0,0 +1,46 @@
{% extends "user/base.html" %}
{% load i18n %}
{% load staticfiles %}
{% block head-title %}{% trans 'Transfer Apps' %} - {% endblock %}
{% block account-content %}
<h1>{% trans "Transfer Apps" %}</h1>
<section>
<p>{% trans 'To transfer an app to a new owner you must first unlock the app. A user can then take control of the app by registering it again on the app register page in the app developer menu.' %}</p>
{% if apps %}
<table class="table table-striped">
<tr>
<th>{% trans 'App name' %}</th>
<th>{% trans 'Ownership transfer status' %}</th>
<th>{% trans 'Change ownership transfer status' %}</th>
</tr>
{% for app in apps %}
<tr>
<td>{{ app.name }}</td>
<td class="{% if app.ownership_transfer_enabled %}bg-success{% else %}bg-danger{% endif %}">
{% if app.ownership_transfer_enabled %}
{% trans 'Unlocked for transfer' %}
{% else %}
{% trans 'Locked, no transfer possible' %}
{% endif %}
</td>
<td>
<form action="{% url 'user:account-transfer-app' pk=app.id %}" method="post">
{% csrf_token %}
{% if app.ownership_transfer_enabled %}
<button class="btn btn-primary btn-block" type="submit">{% trans 'Lock ownership transfer' %}</button>
{% else %}
<button class="btn btn-primary btn-block" type="submit">{% trans 'Unlock ownership transfer' %}</button>
{% endif %}
</form>
</td>
</tr>
{% endfor %}
</table>
{% else %}
<p class="alert alert-info">{% trans 'You have not uploaded any apps yet!' %}</p>
{% endif %}
</section>
{% endblock %}

Просмотреть файл

@ -1,10 +1,14 @@
from django.conf.urls import url
from nextcloudappstore.core.user.views import PasswordView, AccountView, \
APITokenView, DeleteAccountView, ChangeLanguageView
APITokenView, DeleteAccountView, ChangeLanguageView, TransferAppsView
urlpatterns = [
url(r'^$', AccountView.as_view(), name='account'),
url(r'^transfer-apps/?$', TransferAppsView.as_view(),
name='account-transfer-apps'),
url(r'^transfer-apps/(?P<pk>[a-z0-9_]+)/?$', TransferAppsView.as_view(),
name='account-transfer-app'),
url(r'^password/?$', PasswordView.as_view(), name='account-password'),
url(r'^token/?$', APITokenView.as_view(), name='account-api-token'),
url(r'^delete/?$', DeleteAccountView.as_view(), name='account-deletion'),

Просмотреть файл

@ -3,13 +3,31 @@ from allauth.account.views import PasswordChangeView
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import redirect, render
from django.shortcuts import redirect, render, get_object_or_404
from django.urls import reverse
from django.views.generic import TemplateView
from django.views.generic import UpdateView
from nextcloudappstore.core.models import App
from nextcloudappstore.core.user.forms import DeleteAccountForm, AccountForm
class TransferAppsView(LoginRequiredMixin, TemplateView):
template_name = 'user/transfer-apps.html'
def post(self, request, pk):
app = get_object_or_404(App, pk=pk, owner=self.request.user)
app.ownership_transfer_enabled = not app.ownership_transfer_enabled
app.save()
return redirect(reverse('user:account-transfer-apps'))
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['apps'] = App.objects.filter(owner=self.request.user)
context['acc_page'] = 'account-transfer-apps'
return context
class ChangeLanguageView(LoginRequiredMixin, TemplateView):
template_name = 'user/set-language.html'