]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Merge pull request #1675 from wallabag/v2-create-api-client
authorNicolas Lœuillet <nicolas@loeuillet.org>
Tue, 8 Mar 2016 09:09:39 +0000 (10:09 +0100)
committerNicolas Lœuillet <nicolas@loeuillet.org>
Tue, 8 Mar 2016 09:09:39 +0000 (10:09 +0100)
Ability to create new client for the API

15 files changed:
src/Wallabag/CoreBundle/Controller/DeveloperController.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Form/Type/ClientType.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/client.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/client_parameters.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/howto_app.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/index.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/client.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/client_parameters.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/howto_app.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/index.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
src/Wallabag/CoreBundle/Tests/Controller/DeveloperControllerTest.php [new file with mode: 0644]

diff --git a/src/Wallabag/CoreBundle/Controller/DeveloperController.php b/src/Wallabag/CoreBundle/Controller/DeveloperController.php
new file mode 100644 (file)
index 0000000..7106553
--- /dev/null
@@ -0,0 +1,100 @@
+<?php
+
+namespace Wallabag\CoreBundle\Controller;
+
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Wallabag\ApiBundle\Entity\Client;
+use Wallabag\CoreBundle\Form\Type\ClientType;
+
+class DeveloperController extends Controller
+{
+    /**
+     * List all clients and link to create a new one.
+     *
+     * @Route("/developer", name="developer")
+     *
+     * @return \Symfony\Component\HttpFoundation\Response
+     */
+    public function indexAction()
+    {
+        $clients = $this->getDoctrine()->getRepository('WallabagApiBundle:Client')->findAll();
+
+        return $this->render('WallabagCoreBundle:Developer:index.html.twig', array(
+            'clients' => $clients,
+        ));
+    }
+
+    /**
+     * Create a client (an app).
+     *
+     * @param Request $request
+     *
+     * @Route("/developer/client/create", name="developer_create_client")
+     *
+     * @return \Symfony\Component\HttpFoundation\Response
+     */
+    public function createClientAction(Request $request)
+    {
+        $em = $this->getDoctrine()->getManager();
+        $client = new Client();
+        $clientForm = $this->createForm(ClientType::class, $client);
+        $clientForm->handleRequest($request);
+
+        if ($clientForm->isValid()) {
+            $client->setAllowedGrantTypes(array('token', 'authorization_code', 'password'));
+            $em->persist($client);
+            $em->flush();
+
+            $this->get('session')->getFlashBag()->add(
+                'notice',
+                'New client created.'
+            );
+
+            return $this->render('WallabagCoreBundle:Developer:client_parameters.html.twig', array(
+                'client_id' => $client->getPublicId(),
+                'client_secret' => $client->getSecret(),
+            ));
+        }
+
+        return $this->render('WallabagCoreBundle:Developer:client.html.twig', array(
+            'form' => $clientForm->createView(),
+        ));
+    }
+
+    /**
+     * Remove a client.
+     *
+     * @param Client $client
+     *
+     * @Route("/developer/client/delete/{id}", requirements={"id" = "\d+"}, name="developer_delete_client")
+     *
+     * @return \Symfony\Component\HttpFoundation\RedirectResponse
+     */
+    public function deleteClientAction(Client $client)
+    {
+        $em = $this->getDoctrine()->getManager();
+        $em->remove($client);
+        $em->flush();
+
+        $this->get('session')->getFlashBag()->add(
+            'notice',
+            'Client deleted'
+        );
+
+        return $this->redirect($this->generateUrl('developer'));
+    }
+
+    /**
+     * Display developer how to use an existing app.
+     *
+     * @Route("/developer/howto/first-app", name="developer_howto_firstapp")
+     *
+     * @return \Symfony\Component\HttpFoundation\Response
+     */
+    public function howtoFirstAppAction()
+    {
+        return $this->render('WallabagCoreBundle:Developer:howto_app.html.twig');
+    }
+}
diff --git a/src/Wallabag/CoreBundle/Form/Type/ClientType.php b/src/Wallabag/CoreBundle/Form/Type/ClientType.php
new file mode 100644 (file)
index 0000000..dd93471
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+
+namespace Wallabag\CoreBundle\Form\Type;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\CallbackTransformer;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Form\Extension\Core\Type\UrlType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+
+class ClientType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder
+            ->add('redirect_uris', UrlType::class, array('required' => true, 'label' => 'Redirect URIs'))
+            ->add('save', SubmitType::class, array('label' => 'Create a new client'))
+        ;
+
+        $builder->get('redirect_uris')
+            ->addModelTransformer(new CallbackTransformer(
+                function ($originalUri) {
+                    return $originalUri;
+                },
+                function ($submittedUri) {
+                    return array($submittedUri);
+                }
+            ))
+        ;
+    }
+
+    public function configureOptions(OptionsResolver $resolver)
+    {
+        $resolver->setDefaults(array(
+            'data_class' => 'Wallabag\ApiBundle\Entity\Client',
+        ));
+    }
+
+    public function getBlockPrefix()
+    {
+        return 'client';
+    }
+}
index 6c6caa24d430a5cd008d6c2f3302d0d1134875af..b809f1ab8a483e5aa84c977538c1d18f4ea251da 100644 (file)
@@ -242,3 +242,36 @@ If you need some help, we are here for you.: "Parce que vous avez peut-être bes
 On GitHub: "Sur GitHub"
 By email: "Par email"
 On Gitter: "Sur Gitter"
+
+# developer
+Developer: Développeur
+Welcome to the wallabag API: "Bienvenue sur l'API de wallabag"
+How to create my first application: "Comment créer votre première application"
+View full API documentation: "Voir la documentation complète de l'API"
+Clients: "Clients"
+Create a new client: "Créer une nouveau client"
+Existing clients: "Les clients existants"
+Client ID: "ID Client"
+Client secret: "Clé secrète"
+Redirect URIs: "URLs de redirection"
+Grant type allowed: "Type de privilège accordé"
+You have the ability to remove this client. This action is IRREVERSIBLE !: "Vous avez la possibilité de supprimer un client. Cette action est IRREVERSIBLE !"
+If you remove it, every app configured with that client won't be able to auth on your wallabag.: "Si vous supprimez un client, toutes les applications qui l'utilisaient ne fonctionneront plus avec votre compte wallabag."
+Remove this client: "Supprimer ce client"
+New client: "Nouveau client"
+You are about to create a new client. Please fill the field below for the redirect URI of your application.: "Vous allez créer un nouveau client. Merci de remplir l'url de redirection vers votre application."
+Back: "Retour"
+Client parameters: "Les paramètres de votre client"
+New client created.: "Nouveau client créé."
+Here are your client parameters.: "Voilà les paramètres de votre client"
+Read the howto "Create my first application": "Lire \"comment créer ma première application\""
+Client deleted: "Client supprimé"
+No client yet.: "Aucun client pour le moment"
+"The following commands make use of the <a href=\"https://github.com/jkbrzt/httpie\">HTTPie library</a>. Make sure it is installed on your system before using it.": "Les commandes suivantes utilisent la <a href=\"https://github.com/jkbrzt/httpie\">librarie HTTPie</a>. Assurez-vous qu'elle soit installée avant de l'utiliser."
+You need a token to communicate between your 3rd application and wallabag API.: "Vous avez besoin d'un token pour échanger entre votre application et l'API de wallabag."
+"To create this token, you need <a href=\"%link%\">to create a new client</a>.": "Pour créer un token, vous devez <a href=\"%link%\">créer un nouveau client</a>."
+Now, create your token (replace client_id, client_secret, username and password with the good values):: "Maintenant créez votre token (remplacer client_id, client_secret, username et password avec les bonnes valeurs):"
+The API will return a response like this:: "L'API vous retournera une réponse comme ça:"
+The access_token is useful to do a call to the API endpoint. For example:: "L'access_token doit être utilisé pour faire un appel à l'API. Par exemple :"
+This call will return all the entries for your user.: "Cet appel va retourner tous les articles de l'utilisateur."
+"If you want to see all the API endpoints, you can have a look <a href=\"%link%\">to our API documentation</a>.": "Si vous voulez toutes les méthodes de l'API, jetez un oeil <a href=\"%link%\">à la documentation de l'API</a>."
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/client.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/client.html.twig
new file mode 100644 (file)
index 0000000..c9ce6d0
--- /dev/null
@@ -0,0 +1,31 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{% trans %}New client{% endtrans %}{% endblock %}
+
+{% block content %}
+<div class="row">
+    <div class="col s12">
+        <div class="card-panel settings">
+
+            <div class="row">
+                <p>{% trans %}You are about to create a new client. Please fill the field below for the redirect URI of your application.{% endtrans %}</p>
+                {{ form_start(form) }}
+                {{ form_errors(form) }}
+
+                <div class="input-field col s12">
+                    {{ form_label(form.redirect_uris) }}
+                    {{ form_errors(form.redirect_uris) }}
+                    {{ form_widget(form.redirect_uris) }}
+                </div>
+
+                <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a>
+                {{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
+
+                {{ form_rest(form) }}
+            </div>
+
+        </div>
+    </div>
+</div>
+
+{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/client_parameters.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/client_parameters.html.twig
new file mode 100644 (file)
index 0000000..a214dfd
--- /dev/null
@@ -0,0 +1,22 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{% trans %}Client parameters{% endtrans %}{% endblock %}
+
+{% block content %}
+<div class="row">
+    <div class="col s12">
+        <div class="card-panel settings">
+            <div class="row">
+                <p>{% trans %}Here are your client parameters.{% endtrans %}</p>
+                <ul>
+                    <li>{% trans %}Client ID{% endtrans %}: <strong><pre>{{ client_id }}</pre></strong></li>
+                    <li>{% trans %}Client secret{% endtrans %}: <strong><pre>{{ client_secret }}</pre></strong></li>
+                </ul>
+
+                <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a>
+                <a href="{{ path('developer_howto_firstapp') }}" class="btn waves-effect waves-light">{% trans %}Read the howto "Create my first application"{% endtrans %}</a>
+            </div>
+        </div>
+    </div>
+</div>
+{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/howto_app.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/howto_app.html.twig
new file mode 100644 (file)
index 0000000..382e631
--- /dev/null
@@ -0,0 +1,63 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{% trans %}How to create my first application{% endtrans %}{% endblock %}
+
+{% block css %}
+    {{ parent() }}
+    <link rel="stylesheet" href="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/themes/prism-dark.min.css') }}">
+{% endblock %}
+
+{% block content %}
+<div class="row">
+    <div class="col s12">
+        <div class="card-panel settings">
+
+            <div class="row">
+                <p>{% trans %}The following commands make use of the <a href="https://github.com/jkbrzt/httpie">HTTPie library</a>. Make sure it is installed on your system before using it.{% endtrans %}</p>
+                <p>{% trans %}You need a token to communicate between your 3rd application and wallabag API.{% endtrans %}</p>
+                <p>{% trans with {'%link%': path('developer_create_client')} %}To create this token, you need <a href="%link%">to create a new client</a>.{% endtrans %}</p>
+                <p>{% trans %}Now, create your token (replace client_id, client_secret, username and password with the good values):{% endtrans %}</p>
+                <p>
+                    <pre><code class="language-bash">http POST http://v2.wallabag.org/oauth/v2/token \
+    grant_type=password \
+    client_id=12_5um6nz50ceg4088c0840wwc0kgg44g00kk84og044ggkscso0k \
+    client_secret=3qd12zpeaxes8cwg8c0404g888co4wo8kc4gcw0occww8cgw4k \
+    username=yourUsername \
+    password=yourPassw0rd</code></pre>
+                </p>
+                <p>{% trans %}The API will return a response like this:{% endtrans %}</p>
+                <p>
+                    <pre><code class="language-bash">HTTP/1.1 200 OK
+Cache-Control: no-store, private
+Connection: close
+Content-Type: application/json
+Date: Tue, 06 Oct 2015 18:24:03 GMT
+Host: localhost:8000
+Pragma: no-cache
+X-Debug-Token: be00a1
+X-Debug-Token-Link: /profiler/be00a1
+X-Powered-By: PHP/5.5.9-1ubuntu4.13
+{
+    "access_token": "ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw",
+    "expires_in": 3600,
+    "refresh_token": "ODBjODU1NWUwNmUzZTBkNDQ5YWVlZTVlMjQ2Y2I0OWM2NTM1ZGM2M2Y3MDhjMTViM2U2MzYxYzRkMDk5ODRlZg",
+    "scope": null,
+    "token_type": "bearer"
+}</code></pre>
+                </p>
+                <p>{% trans %}The access_token is useful to do a call to the API endpoint. For example:{% endtrans %}</p>
+                <p>
+                    <pre><code class="language-bash">http GET http://v2.wallabag.org/api/entries.json \
+    "Authorization:Bearer ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw"</code></pre>
+                </p>
+                <p>{% trans %}This call will return all the entries for your user.{% endtrans %}</p>
+                <p>{% trans with {'%link%': path('nelmio_api_doc_index')} %}If you want to see all the API endpoints, you can have a look <a href="%link%">to our API documentation</a>.{% endtrans %}</p>
+                <p><a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a></p>
+            </div>
+
+        </div>
+    </div>
+</div>
+<script src="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/prism.min.js') }}"></script>
+<script src="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/components/prism-bash.min.js') }}"></script>
+{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/index.html.twig
new file mode 100644 (file)
index 0000000..2e7dbca
--- /dev/null
@@ -0,0 +1,68 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{% trans %}Developer{% endtrans %}{% endblock %}
+
+{% block content %}
+<div class="row">
+    <div class="col s12">
+        <div class="card-panel settings">
+
+            <div class="row">
+                <h3>{% trans %}Welcome to the wallabag API{% endtrans %}</h3>
+
+                <h4>{% trans %}Documentation{% endtrans %}</h4>
+
+                <ul>
+                    <li><a href="{{ path('developer_howto_firstapp') }}">{% trans %}How to create my first application{% endtrans %}</a></li>
+                    <li><a href="{{ path('nelmio_api_doc_index') }}">{% trans %}View full API documentation{% endtrans %}</a></li>
+                </ul>
+
+                <h4>{% trans %}Clients{% endtrans %}</h4>
+                <ul>
+                    <li><a href="{{ path('developer_create_client') }}">{% trans %}Create a new client{% endtrans %}</a></li>
+                </ul>
+
+                <h4>{% trans %}Existing clients{% endtrans %}</h4>
+                {% if clients %}
+                    <ul class="collapsible" data-collapsible="expandable">
+                        {% for client in clients %}
+                            <li>
+                                <div class="collapsible-header">#{{ client.id }}</div>
+                                <div class="collapsible-body">
+                                    <table class="striped">
+                                        <tr>
+                                            <td>{% trans %}Client ID{% endtrans %}</td>
+                                            <td><strong><code>{{ client.id }}_{{ client.randomId }}</code></strong></td>
+                                        </tr>
+                                        <tr>
+                                            <td>{% trans %}Client secret{% endtrans %}</td>
+                                            <td><strong><code>{{ client.secret }}</code></strong></td>
+                                        </tr>
+                                        <tr>
+                                            <td>{% trans %}Redirect URIs{% endtrans %}</td>
+                                            <td><strong><code>{{ client.redirectUris|json_encode() }}</code></strong></td>
+                                        </tr>
+                                        <tr>
+                                            <td>{% trans %}Grant type allowed{% endtrans %}</td>
+                                            <td><strong><code>{{ client.allowedGrantTypes|json_encode() }}</code></strong></td>
+                                        </tr>
+                                    </table>
+                                    <p>
+                                        {% trans %}You have the ability to remove this client. This action is IRREVERSIBLE !{% endtrans %}<br/>
+                                        {% trans %}If you remove it, every app configured with that client won't be able to auth on your wallabag.{% endtrans %}<br/>
+                                        <a class="waves-effect waves-light red btn" href="{{ path('developer_delete_client', {'id': client.id}) }}">{% trans %}Remove this client{% endtrans %}</a>
+                                    </p>
+                                </div>
+                            </li>
+                        {% endfor %}
+                    </ul>
+                {% else %}
+                    {% trans %}No client yet.{% endtrans %}
+                {% endif %}
+            </div>
+
+        </div>
+    </div>
+</div>
+
+{% endblock %}
index 84604762dd8e3ab411b733a04145f5cecf18931b..7f0980660298d4f170a985746550eaa0c1a180df 100644 (file)
@@ -56,6 +56,7 @@
         {% endif %}
         <li><a href="{{ path('import') }}">{% trans %}import{% endtrans %}</a></li>
         <li><a href="{{ path('howto') }}">{% trans %}howto{% endtrans %}</a></li>
+        <li><a href="{{ path('developer') }}">{% trans %}Developer{% endtrans %}</a></li>
         <li><a href="{{ path('about') }}">{% trans %}about{% endtrans %}</a></li>
         <li><a class="icon icon-power" href="{{ path('fos_user_security_logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li>
     </ul>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/client.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/client.html.twig
new file mode 100644 (file)
index 0000000..c9ce6d0
--- /dev/null
@@ -0,0 +1,31 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{% trans %}New client{% endtrans %}{% endblock %}
+
+{% block content %}
+<div class="row">
+    <div class="col s12">
+        <div class="card-panel settings">
+
+            <div class="row">
+                <p>{% trans %}You are about to create a new client. Please fill the field below for the redirect URI of your application.{% endtrans %}</p>
+                {{ form_start(form) }}
+                {{ form_errors(form) }}
+
+                <div class="input-field col s12">
+                    {{ form_label(form.redirect_uris) }}
+                    {{ form_errors(form.redirect_uris) }}
+                    {{ form_widget(form.redirect_uris) }}
+                </div>
+
+                <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a>
+                {{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
+
+                {{ form_rest(form) }}
+            </div>
+
+        </div>
+    </div>
+</div>
+
+{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/client_parameters.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/client_parameters.html.twig
new file mode 100644 (file)
index 0000000..a214dfd
--- /dev/null
@@ -0,0 +1,22 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{% trans %}Client parameters{% endtrans %}{% endblock %}
+
+{% block content %}
+<div class="row">
+    <div class="col s12">
+        <div class="card-panel settings">
+            <div class="row">
+                <p>{% trans %}Here are your client parameters.{% endtrans %}</p>
+                <ul>
+                    <li>{% trans %}Client ID{% endtrans %}: <strong><pre>{{ client_id }}</pre></strong></li>
+                    <li>{% trans %}Client secret{% endtrans %}: <strong><pre>{{ client_secret }}</pre></strong></li>
+                </ul>
+
+                <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a>
+                <a href="{{ path('developer_howto_firstapp') }}" class="btn waves-effect waves-light">{% trans %}Read the howto "Create my first application"{% endtrans %}</a>
+            </div>
+        </div>
+    </div>
+</div>
+{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/howto_app.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/howto_app.html.twig
new file mode 100644 (file)
index 0000000..382e631
--- /dev/null
@@ -0,0 +1,63 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{% trans %}How to create my first application{% endtrans %}{% endblock %}
+
+{% block css %}
+    {{ parent() }}
+    <link rel="stylesheet" href="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/themes/prism-dark.min.css') }}">
+{% endblock %}
+
+{% block content %}
+<div class="row">
+    <div class="col s12">
+        <div class="card-panel settings">
+
+            <div class="row">
+                <p>{% trans %}The following commands make use of the <a href="https://github.com/jkbrzt/httpie">HTTPie library</a>. Make sure it is installed on your system before using it.{% endtrans %}</p>
+                <p>{% trans %}You need a token to communicate between your 3rd application and wallabag API.{% endtrans %}</p>
+                <p>{% trans with {'%link%': path('developer_create_client')} %}To create this token, you need <a href="%link%">to create a new client</a>.{% endtrans %}</p>
+                <p>{% trans %}Now, create your token (replace client_id, client_secret, username and password with the good values):{% endtrans %}</p>
+                <p>
+                    <pre><code class="language-bash">http POST http://v2.wallabag.org/oauth/v2/token \
+    grant_type=password \
+    client_id=12_5um6nz50ceg4088c0840wwc0kgg44g00kk84og044ggkscso0k \
+    client_secret=3qd12zpeaxes8cwg8c0404g888co4wo8kc4gcw0occww8cgw4k \
+    username=yourUsername \
+    password=yourPassw0rd</code></pre>
+                </p>
+                <p>{% trans %}The API will return a response like this:{% endtrans %}</p>
+                <p>
+                    <pre><code class="language-bash">HTTP/1.1 200 OK
+Cache-Control: no-store, private
+Connection: close
+Content-Type: application/json
+Date: Tue, 06 Oct 2015 18:24:03 GMT
+Host: localhost:8000
+Pragma: no-cache
+X-Debug-Token: be00a1
+X-Debug-Token-Link: /profiler/be00a1
+X-Powered-By: PHP/5.5.9-1ubuntu4.13
+{
+    "access_token": "ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw",
+    "expires_in": 3600,
+    "refresh_token": "ODBjODU1NWUwNmUzZTBkNDQ5YWVlZTVlMjQ2Y2I0OWM2NTM1ZGM2M2Y3MDhjMTViM2U2MzYxYzRkMDk5ODRlZg",
+    "scope": null,
+    "token_type": "bearer"
+}</code></pre>
+                </p>
+                <p>{% trans %}The access_token is useful to do a call to the API endpoint. For example:{% endtrans %}</p>
+                <p>
+                    <pre><code class="language-bash">http GET http://v2.wallabag.org/api/entries.json \
+    "Authorization:Bearer ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw"</code></pre>
+                </p>
+                <p>{% trans %}This call will return all the entries for your user.{% endtrans %}</p>
+                <p>{% trans with {'%link%': path('nelmio_api_doc_index')} %}If you want to see all the API endpoints, you can have a look <a href="%link%">to our API documentation</a>.{% endtrans %}</p>
+                <p><a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a></p>
+            </div>
+
+        </div>
+    </div>
+</div>
+<script src="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/prism.min.js') }}"></script>
+<script src="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/components/prism-bash.min.js') }}"></script>
+{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/index.html.twig
new file mode 100644 (file)
index 0000000..2e7dbca
--- /dev/null
@@ -0,0 +1,68 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{% trans %}Developer{% endtrans %}{% endblock %}
+
+{% block content %}
+<div class="row">
+    <div class="col s12">
+        <div class="card-panel settings">
+
+            <div class="row">
+                <h3>{% trans %}Welcome to the wallabag API{% endtrans %}</h3>
+
+                <h4>{% trans %}Documentation{% endtrans %}</h4>
+
+                <ul>
+                    <li><a href="{{ path('developer_howto_firstapp') }}">{% trans %}How to create my first application{% endtrans %}</a></li>
+                    <li><a href="{{ path('nelmio_api_doc_index') }}">{% trans %}View full API documentation{% endtrans %}</a></li>
+                </ul>
+
+                <h4>{% trans %}Clients{% endtrans %}</h4>
+                <ul>
+                    <li><a href="{{ path('developer_create_client') }}">{% trans %}Create a new client{% endtrans %}</a></li>
+                </ul>
+
+                <h4>{% trans %}Existing clients{% endtrans %}</h4>
+                {% if clients %}
+                    <ul class="collapsible" data-collapsible="expandable">
+                        {% for client in clients %}
+                            <li>
+                                <div class="collapsible-header">#{{ client.id }}</div>
+                                <div class="collapsible-body">
+                                    <table class="striped">
+                                        <tr>
+                                            <td>{% trans %}Client ID{% endtrans %}</td>
+                                            <td><strong><code>{{ client.id }}_{{ client.randomId }}</code></strong></td>
+                                        </tr>
+                                        <tr>
+                                            <td>{% trans %}Client secret{% endtrans %}</td>
+                                            <td><strong><code>{{ client.secret }}</code></strong></td>
+                                        </tr>
+                                        <tr>
+                                            <td>{% trans %}Redirect URIs{% endtrans %}</td>
+                                            <td><strong><code>{{ client.redirectUris|json_encode() }}</code></strong></td>
+                                        </tr>
+                                        <tr>
+                                            <td>{% trans %}Grant type allowed{% endtrans %}</td>
+                                            <td><strong><code>{{ client.allowedGrantTypes|json_encode() }}</code></strong></td>
+                                        </tr>
+                                    </table>
+                                    <p>
+                                        {% trans %}You have the ability to remove this client. This action is IRREVERSIBLE !{% endtrans %}<br/>
+                                        {% trans %}If you remove it, every app configured with that client won't be able to auth on your wallabag.{% endtrans %}<br/>
+                                        <a class="waves-effect waves-light red btn" href="{{ path('developer_delete_client', {'id': client.id}) }}">{% trans %}Remove this client{% endtrans %}</a>
+                                    </p>
+                                </div>
+                            </li>
+                        {% endfor %}
+                    </ul>
+                {% else %}
+                    {% trans %}No client yet.{% endtrans %}
+                {% endif %}
+            </div>
+
+        </div>
+    </div>
+</div>
+
+{% endblock %}
index 3d21271adddb03f7a70270ee3fa6d810f6557e65..dea4242b4491619e97d36750118b2983c58fc311 100644 (file)
                         <li><a href="{{ path('import_wallabag_v1') }}">{% trans %}Migrate from wallabag v1{% endtrans %}</a></li>
                         <li><a href="{{ path('import_wallabag_v2') }}">{% trans %}Migrate from wallabag v2{% endtrans %}</a></li>
                     </ul>
+                    <h4>{% trans %}Developers{% endtrans %}</h4>
+                    <ul>
+                        <li><a href="{{ path('developer') }}">{% trans %}Create your third application{% endtrans %}</a></li>
+                    </ul>
                     <h4>{% trans %}Full documentation{% endtrans %}</h4>
                     <ul>
                         <li><a href="http://wallabag.readthedocs.org">{% trans %}Annotate your article{% endtrans %}</a></li>
index d7bfa7aede2ab106b96f4ae37c534fdc9316d85a..f5d03084d1c6f4af01070e94e6e14062b7f6954b 100644 (file)
@@ -50,6 +50,7 @@
             {% endif %}
             <li class="bold {% if currentRoute == 'import' %}active{% endif %}"><a class="waves-effect" href="{{ path('import') }}">{% trans %}import{% endtrans %}</a></li>
             <li class="bold {% if currentRoute == 'howto' %}active{% endif %}"><a class="waves-effect" href="{{ path('howto') }}">{% trans %}howto{% endtrans %}</a></li>
+            <li class="bold {% if currentRoute == 'developer' %}active{% endif %}"><a class="waves-effect" href="{{ path('developer') }}">{% trans %}Developer{% endtrans %}</a></li>
             <li class="bold"><a class="waves-effect" class="icon icon-power" href="{{ path('fos_user_security_logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li>
         </ul>
         <div class="nav-wrapper nav-panels">
diff --git a/src/Wallabag/CoreBundle/Tests/Controller/DeveloperControllerTest.php b/src/Wallabag/CoreBundle/Tests/Controller/DeveloperControllerTest.php
new file mode 100644 (file)
index 0000000..fc220b8
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+
+namespace Wallabag\CoreBundle\Tests\Controller;
+
+use Wallabag\CoreBundle\Tests\WallabagCoreTestCase;
+
+class DeveloperControllerTest extends WallabagCoreTestCase
+{
+    public function testCreateClient()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+        $em = $client->getContainer()->get('doctrine.orm.entity_manager');
+        $nbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
+
+        $crawler = $client->request('GET', '/developer/client/create');
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $form = $crawler->filter('button[type=submit]')->form();
+
+        $client->submit($form);
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $newNbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
+        $this->assertGreaterThan(count($nbClients), count($newNbClients));
+    }
+
+    public function testListingClient()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+        $em = $client->getContainer()->get('doctrine.orm.entity_manager');
+        $nbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
+
+        $crawler = $client->request('GET', '/developer');
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+        $this->assertEquals(count($nbClients), $crawler->filter('ul[class=collapsible] li')->count());
+    }
+
+    public function testDeveloperHowto()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/developer/howto/first-app');
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+    }
+
+    public function testRemoveClient()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+        $em = $client->getContainer()->get('doctrine.orm.entity_manager');
+        $nbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
+
+        $crawler = $client->request('GET', '/developer');
+
+        $link = $crawler
+            ->filter('div[class=collapsible-body] p a')
+            ->eq(0)
+            ->link()
+        ;
+
+        $client->click($link);
+        $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+        $newNbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
+        $this->assertGreaterThan(count($newNbClients), count($nbClients));
+    }
+}