aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorNicolas Lœuillet <nicolas@loeuillet.org>2016-03-08 10:09:39 +0100
committerNicolas Lœuillet <nicolas@loeuillet.org>2016-03-08 10:09:39 +0100
commit807037884f0085cd39fe4b41cacd82be14e309d9 (patch)
treea0e01ec2268faa2415e814c38549ae065e32bb7c /src
parent1e5a4b36ab9e50047e48f247b84733bdf9417844 (diff)
parentd11eb2e461a3ea2b74e5a1c686c9fa9bbcb9e103 (diff)
downloadwallabag-807037884f0085cd39fe4b41cacd82be14e309d9.tar.gz
wallabag-807037884f0085cd39fe4b41cacd82be14e309d9.tar.zst
wallabag-807037884f0085cd39fe4b41cacd82be14e309d9.zip
Merge pull request #1675 from wallabag/v2-create-api-client
Ability to create new client for the API
Diffstat (limited to 'src')
-rw-r--r--src/Wallabag/CoreBundle/Controller/DeveloperController.php100
-rw-r--r--src/Wallabag/CoreBundle/Form/Type/ClientType.php44
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml33
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/client.html.twig31
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/client_parameters.html.twig22
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/howto_app.html.twig63
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/index.html.twig68
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig1
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/client.html.twig31
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/client_parameters.html.twig22
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/howto_app.html.twig63
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/index.html.twig68
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig4
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig1
-rw-r--r--src/Wallabag/CoreBundle/Tests/Controller/DeveloperControllerTest.php71
15 files changed, 622 insertions, 0 deletions
diff --git a/src/Wallabag/CoreBundle/Controller/DeveloperController.php b/src/Wallabag/CoreBundle/Controller/DeveloperController.php
new file mode 100644
index 00000000..71065534
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Controller/DeveloperController.php
@@ -0,0 +1,100 @@
1<?php
2
3namespace Wallabag\CoreBundle\Controller;
4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Component\HttpFoundation\Request;
7use Symfony\Bundle\FrameworkBundle\Controller\Controller;
8use Wallabag\ApiBundle\Entity\Client;
9use Wallabag\CoreBundle\Form\Type\ClientType;
10
11class DeveloperController extends Controller
12{
13 /**
14 * List all clients and link to create a new one.
15 *
16 * @Route("/developer", name="developer")
17 *
18 * @return \Symfony\Component\HttpFoundation\Response
19 */
20 public function indexAction()
21 {
22 $clients = $this->getDoctrine()->getRepository('WallabagApiBundle:Client')->findAll();
23
24 return $this->render('WallabagCoreBundle:Developer:index.html.twig', array(
25 'clients' => $clients,
26 ));
27 }
28
29 /**
30 * Create a client (an app).
31 *
32 * @param Request $request
33 *
34 * @Route("/developer/client/create", name="developer_create_client")
35 *
36 * @return \Symfony\Component\HttpFoundation\Response
37 */
38 public function createClientAction(Request $request)
39 {
40 $em = $this->getDoctrine()->getManager();
41 $client = new Client();
42 $clientForm = $this->createForm(ClientType::class, $client);
43 $clientForm->handleRequest($request);
44
45 if ($clientForm->isValid()) {
46 $client->setAllowedGrantTypes(array('token', 'authorization_code', 'password'));
47 $em->persist($client);
48 $em->flush();
49
50 $this->get('session')->getFlashBag()->add(
51 'notice',
52 'New client created.'
53 );
54
55 return $this->render('WallabagCoreBundle:Developer:client_parameters.html.twig', array(
56 'client_id' => $client->getPublicId(),
57 'client_secret' => $client->getSecret(),
58 ));
59 }
60
61 return $this->render('WallabagCoreBundle:Developer:client.html.twig', array(
62 'form' => $clientForm->createView(),
63 ));
64 }
65
66 /**
67 * Remove a client.
68 *
69 * @param Client $client
70 *
71 * @Route("/developer/client/delete/{id}", requirements={"id" = "\d+"}, name="developer_delete_client")
72 *
73 * @return \Symfony\Component\HttpFoundation\RedirectResponse
74 */
75 public function deleteClientAction(Client $client)
76 {
77 $em = $this->getDoctrine()->getManager();
78 $em->remove($client);
79 $em->flush();
80
81 $this->get('session')->getFlashBag()->add(
82 'notice',
83 'Client deleted'
84 );
85
86 return $this->redirect($this->generateUrl('developer'));
87 }
88
89 /**
90 * Display developer how to use an existing app.
91 *
92 * @Route("/developer/howto/first-app", name="developer_howto_firstapp")
93 *
94 * @return \Symfony\Component\HttpFoundation\Response
95 */
96 public function howtoFirstAppAction()
97 {
98 return $this->render('WallabagCoreBundle:Developer:howto_app.html.twig');
99 }
100}
diff --git a/src/Wallabag/CoreBundle/Form/Type/ClientType.php b/src/Wallabag/CoreBundle/Form/Type/ClientType.php
new file mode 100644
index 00000000..dd934715
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Form/Type/ClientType.php
@@ -0,0 +1,44 @@
1<?php
2
3namespace Wallabag\CoreBundle\Form\Type;
4
5use Symfony\Component\Form\AbstractType;
6use Symfony\Component\Form\CallbackTransformer;
7use Symfony\Component\Form\Extension\Core\Type\SubmitType;
8use Symfony\Component\Form\Extension\Core\Type\UrlType;
9use Symfony\Component\Form\FormBuilderInterface;
10use Symfony\Component\OptionsResolver\OptionsResolver;
11
12class ClientType extends AbstractType
13{
14 public function buildForm(FormBuilderInterface $builder, array $options)
15 {
16 $builder
17 ->add('redirect_uris', UrlType::class, array('required' => true, 'label' => 'Redirect URIs'))
18 ->add('save', SubmitType::class, array('label' => 'Create a new client'))
19 ;
20
21 $builder->get('redirect_uris')
22 ->addModelTransformer(new CallbackTransformer(
23 function ($originalUri) {
24 return $originalUri;
25 },
26 function ($submittedUri) {
27 return array($submittedUri);
28 }
29 ))
30 ;
31 }
32
33 public function configureOptions(OptionsResolver $resolver)
34 {
35 $resolver->setDefaults(array(
36 'data_class' => 'Wallabag\ApiBundle\Entity\Client',
37 ));
38 }
39
40 public function getBlockPrefix()
41 {
42 return 'client';
43 }
44}
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
index 6c6caa24..b809f1ab 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
@@ -242,3 +242,36 @@ If you need some help, we are here for you.: "Parce que vous avez peut-être bes
242On GitHub: "Sur GitHub" 242On GitHub: "Sur GitHub"
243By email: "Par email" 243By email: "Par email"
244On Gitter: "Sur Gitter" 244On Gitter: "Sur Gitter"
245
246# developer
247Developer: Développeur
248Welcome to the wallabag API: "Bienvenue sur l'API de wallabag"
249How to create my first application: "Comment créer votre première application"
250View full API documentation: "Voir la documentation complète de l'API"
251Clients: "Clients"
252Create a new client: "Créer une nouveau client"
253Existing clients: "Les clients existants"
254Client ID: "ID Client"
255Client secret: "Clé secrète"
256Redirect URIs: "URLs de redirection"
257Grant type allowed: "Type de privilège accordé"
258You have the ability to remove this client. This action is IRREVERSIBLE !: "Vous avez la possibilité de supprimer un client. Cette action est IRREVERSIBLE !"
259If 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."
260Remove this client: "Supprimer ce client"
261New client: "Nouveau client"
262You 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."
263Back: "Retour"
264Client parameters: "Les paramètres de votre client"
265New client created.: "Nouveau client créé."
266Here are your client parameters.: "Voilà les paramètres de votre client"
267Read the howto "Create my first application": "Lire \"comment créer ma première application\""
268Client deleted: "Client supprimé"
269No client yet.: "Aucun client pour le moment"
270"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."
271You 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."
272"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>."
273Now, 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):"
274The API will return a response like this:: "L'API vous retournera une réponse comme ça:"
275The 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 :"
276This call will return all the entries for your user.: "Cet appel va retourner tous les articles de l'utilisateur."
277"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
index 00000000..c9ce6d08
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/client.html.twig
@@ -0,0 +1,31 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{% trans %}New client{% endtrans %}{% endblock %}
4
5{% block content %}
6<div class="row">
7 <div class="col s12">
8 <div class="card-panel settings">
9
10 <div class="row">
11 <p>{% trans %}You are about to create a new client. Please fill the field below for the redirect URI of your application.{% endtrans %}</p>
12 {{ form_start(form) }}
13 {{ form_errors(form) }}
14
15 <div class="input-field col s12">
16 {{ form_label(form.redirect_uris) }}
17 {{ form_errors(form.redirect_uris) }}
18 {{ form_widget(form.redirect_uris) }}
19 </div>
20
21 <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a>
22 {{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
23
24 {{ form_rest(form) }}
25 </div>
26
27 </div>
28 </div>
29</div>
30
31{% 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
index 00000000..a214dfd0
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/client_parameters.html.twig
@@ -0,0 +1,22 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{% trans %}Client parameters{% endtrans %}{% endblock %}
4
5{% block content %}
6<div class="row">
7 <div class="col s12">
8 <div class="card-panel settings">
9 <div class="row">
10 <p>{% trans %}Here are your client parameters.{% endtrans %}</p>
11 <ul>
12 <li>{% trans %}Client ID{% endtrans %}: <strong><pre>{{ client_id }}</pre></strong></li>
13 <li>{% trans %}Client secret{% endtrans %}: <strong><pre>{{ client_secret }}</pre></strong></li>
14 </ul>
15
16 <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a>
17 <a href="{{ path('developer_howto_firstapp') }}" class="btn waves-effect waves-light">{% trans %}Read the howto "Create my first application"{% endtrans %}</a>
18 </div>
19 </div>
20 </div>
21</div>
22{% 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
index 00000000..382e6311
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/howto_app.html.twig
@@ -0,0 +1,63 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{% trans %}How to create my first application{% endtrans %}{% endblock %}
4
5{% block css %}
6 {{ parent() }}
7 <link rel="stylesheet" href="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/themes/prism-dark.min.css') }}">
8{% endblock %}
9
10{% block content %}
11<div class="row">
12 <div class="col s12">
13 <div class="card-panel settings">
14
15 <div class="row">
16 <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>
17 <p>{% trans %}You need a token to communicate between your 3rd application and wallabag API.{% endtrans %}</p>
18 <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>
19 <p>{% trans %}Now, create your token (replace client_id, client_secret, username and password with the good values):{% endtrans %}</p>
20 <p>
21 <pre><code class="language-bash">http POST http://v2.wallabag.org/oauth/v2/token \
22 grant_type=password \
23 client_id=12_5um6nz50ceg4088c0840wwc0kgg44g00kk84og044ggkscso0k \
24 client_secret=3qd12zpeaxes8cwg8c0404g888co4wo8kc4gcw0occww8cgw4k \
25 username=yourUsername \
26 password=yourPassw0rd</code></pre>
27 </p>
28 <p>{% trans %}The API will return a response like this:{% endtrans %}</p>
29 <p>
30 <pre><code class="language-bash">HTTP/1.1 200 OK
31Cache-Control: no-store, private
32Connection: close
33Content-Type: application/json
34Date: Tue, 06 Oct 2015 18:24:03 GMT
35Host: localhost:8000
36Pragma: no-cache
37X-Debug-Token: be00a1
38X-Debug-Token-Link: /profiler/be00a1
39X-Powered-By: PHP/5.5.9-1ubuntu4.13
40{
41 "access_token": "ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw",
42 "expires_in": 3600,
43 "refresh_token": "ODBjODU1NWUwNmUzZTBkNDQ5YWVlZTVlMjQ2Y2I0OWM2NTM1ZGM2M2Y3MDhjMTViM2U2MzYxYzRkMDk5ODRlZg",
44 "scope": null,
45 "token_type": "bearer"
46}</code></pre>
47 </p>
48 <p>{% trans %}The access_token is useful to do a call to the API endpoint. For example:{% endtrans %}</p>
49 <p>
50 <pre><code class="language-bash">http GET http://v2.wallabag.org/api/entries.json \
51 "Authorization:Bearer ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw"</code></pre>
52 </p>
53 <p>{% trans %}This call will return all the entries for your user.{% endtrans %}</p>
54 <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>
55 <p><a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a></p>
56 </div>
57
58 </div>
59 </div>
60</div>
61<script src="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/prism.min.js') }}"></script>
62<script src="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/components/prism-bash.min.js') }}"></script>
63{% 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
index 00000000..2e7dbcab
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Developer/index.html.twig
@@ -0,0 +1,68 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{% trans %}Developer{% endtrans %}{% endblock %}
4
5{% block content %}
6<div class="row">
7 <div class="col s12">
8 <div class="card-panel settings">
9
10 <div class="row">
11 <h3>{% trans %}Welcome to the wallabag API{% endtrans %}</h3>
12
13 <h4>{% trans %}Documentation{% endtrans %}</h4>
14
15 <ul>
16 <li><a href="{{ path('developer_howto_firstapp') }}">{% trans %}How to create my first application{% endtrans %}</a></li>
17 <li><a href="{{ path('nelmio_api_doc_index') }}">{% trans %}View full API documentation{% endtrans %}</a></li>
18 </ul>
19
20 <h4>{% trans %}Clients{% endtrans %}</h4>
21 <ul>
22 <li><a href="{{ path('developer_create_client') }}">{% trans %}Create a new client{% endtrans %}</a></li>
23 </ul>
24
25 <h4>{% trans %}Existing clients{% endtrans %}</h4>
26 {% if clients %}
27 <ul class="collapsible" data-collapsible="expandable">
28 {% for client in clients %}
29 <li>
30 <div class="collapsible-header">#{{ client.id }}</div>
31 <div class="collapsible-body">
32 <table class="striped">
33 <tr>
34 <td>{% trans %}Client ID{% endtrans %}</td>
35 <td><strong><code>{{ client.id }}_{{ client.randomId }}</code></strong></td>
36 </tr>
37 <tr>
38 <td>{% trans %}Client secret{% endtrans %}</td>
39 <td><strong><code>{{ client.secret }}</code></strong></td>
40 </tr>
41 <tr>
42 <td>{% trans %}Redirect URIs{% endtrans %}</td>
43 <td><strong><code>{{ client.redirectUris|json_encode() }}</code></strong></td>
44 </tr>
45 <tr>
46 <td>{% trans %}Grant type allowed{% endtrans %}</td>
47 <td><strong><code>{{ client.allowedGrantTypes|json_encode() }}</code></strong></td>
48 </tr>
49 </table>
50 <p>
51 {% trans %}You have the ability to remove this client. This action is IRREVERSIBLE !{% endtrans %}<br/>
52 {% trans %}If you remove it, every app configured with that client won't be able to auth on your wallabag.{% endtrans %}<br/>
53 <a class="waves-effect waves-light red btn" href="{{ path('developer_delete_client', {'id': client.id}) }}">{% trans %}Remove this client{% endtrans %}</a>
54 </p>
55 </div>
56 </li>
57 {% endfor %}
58 </ul>
59 {% else %}
60 {% trans %}No client yet.{% endtrans %}
61 {% endif %}
62 </div>
63
64 </div>
65 </div>
66</div>
67
68{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
index 84604762..7f098066 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
@@ -56,6 +56,7 @@
56 {% endif %} 56 {% endif %}
57 <li><a href="{{ path('import') }}">{% trans %}import{% endtrans %}</a></li> 57 <li><a href="{{ path('import') }}">{% trans %}import{% endtrans %}</a></li>
58 <li><a href="{{ path('howto') }}">{% trans %}howto{% endtrans %}</a></li> 58 <li><a href="{{ path('howto') }}">{% trans %}howto{% endtrans %}</a></li>
59 <li><a href="{{ path('developer') }}">{% trans %}Developer{% endtrans %}</a></li>
59 <li><a href="{{ path('about') }}">{% trans %}about{% endtrans %}</a></li> 60 <li><a href="{{ path('about') }}">{% trans %}about{% endtrans %}</a></li>
60 <li><a class="icon icon-power" href="{{ path('fos_user_security_logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li> 61 <li><a class="icon icon-power" href="{{ path('fos_user_security_logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li>
61 </ul> 62 </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
index 00000000..c9ce6d08
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/client.html.twig
@@ -0,0 +1,31 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{% trans %}New client{% endtrans %}{% endblock %}
4
5{% block content %}
6<div class="row">
7 <div class="col s12">
8 <div class="card-panel settings">
9
10 <div class="row">
11 <p>{% trans %}You are about to create a new client. Please fill the field below for the redirect URI of your application.{% endtrans %}</p>
12 {{ form_start(form) }}
13 {{ form_errors(form) }}
14
15 <div class="input-field col s12">
16 {{ form_label(form.redirect_uris) }}
17 {{ form_errors(form.redirect_uris) }}
18 {{ form_widget(form.redirect_uris) }}
19 </div>
20
21 <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a>
22 {{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
23
24 {{ form_rest(form) }}
25 </div>
26
27 </div>
28 </div>
29</div>
30
31{% 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
index 00000000..a214dfd0
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/client_parameters.html.twig
@@ -0,0 +1,22 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{% trans %}Client parameters{% endtrans %}{% endblock %}
4
5{% block content %}
6<div class="row">
7 <div class="col s12">
8 <div class="card-panel settings">
9 <div class="row">
10 <p>{% trans %}Here are your client parameters.{% endtrans %}</p>
11 <ul>
12 <li>{% trans %}Client ID{% endtrans %}: <strong><pre>{{ client_id }}</pre></strong></li>
13 <li>{% trans %}Client secret{% endtrans %}: <strong><pre>{{ client_secret }}</pre></strong></li>
14 </ul>
15
16 <a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a>
17 <a href="{{ path('developer_howto_firstapp') }}" class="btn waves-effect waves-light">{% trans %}Read the howto "Create my first application"{% endtrans %}</a>
18 </div>
19 </div>
20 </div>
21</div>
22{% 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
index 00000000..382e6311
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/howto_app.html.twig
@@ -0,0 +1,63 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{% trans %}How to create my first application{% endtrans %}{% endblock %}
4
5{% block css %}
6 {{ parent() }}
7 <link rel="stylesheet" href="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/themes/prism-dark.min.css') }}">
8{% endblock %}
9
10{% block content %}
11<div class="row">
12 <div class="col s12">
13 <div class="card-panel settings">
14
15 <div class="row">
16 <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>
17 <p>{% trans %}You need a token to communicate between your 3rd application and wallabag API.{% endtrans %}</p>
18 <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>
19 <p>{% trans %}Now, create your token (replace client_id, client_secret, username and password with the good values):{% endtrans %}</p>
20 <p>
21 <pre><code class="language-bash">http POST http://v2.wallabag.org/oauth/v2/token \
22 grant_type=password \
23 client_id=12_5um6nz50ceg4088c0840wwc0kgg44g00kk84og044ggkscso0k \
24 client_secret=3qd12zpeaxes8cwg8c0404g888co4wo8kc4gcw0occww8cgw4k \
25 username=yourUsername \
26 password=yourPassw0rd</code></pre>
27 </p>
28 <p>{% trans %}The API will return a response like this:{% endtrans %}</p>
29 <p>
30 <pre><code class="language-bash">HTTP/1.1 200 OK
31Cache-Control: no-store, private
32Connection: close
33Content-Type: application/json
34Date: Tue, 06 Oct 2015 18:24:03 GMT
35Host: localhost:8000
36Pragma: no-cache
37X-Debug-Token: be00a1
38X-Debug-Token-Link: /profiler/be00a1
39X-Powered-By: PHP/5.5.9-1ubuntu4.13
40{
41 "access_token": "ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw",
42 "expires_in": 3600,
43 "refresh_token": "ODBjODU1NWUwNmUzZTBkNDQ5YWVlZTVlMjQ2Y2I0OWM2NTM1ZGM2M2Y3MDhjMTViM2U2MzYxYzRkMDk5ODRlZg",
44 "scope": null,
45 "token_type": "bearer"
46}</code></pre>
47 </p>
48 <p>{% trans %}The access_token is useful to do a call to the API endpoint. For example:{% endtrans %}</p>
49 <p>
50 <pre><code class="language-bash">http GET http://v2.wallabag.org/api/entries.json \
51 "Authorization:Bearer ZWFjNjA3ZWMwYWVmYzRkYTBlMmQ3NTllYmVhOGJiZDE0ZTg1NjE4MjczOTVlNzM0ZTRlMWQ0MmRlMmYwNTk5Mw"</code></pre>
52 </p>
53 <p>{% trans %}This call will return all the entries for your user.{% endtrans %}</p>
54 <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>
55 <p><a href="{{ path('developer') }}" class="waves-effect waves-light grey btn">{% trans %}Back{% endtrans %}</a></p>
56 </div>
57
58 </div>
59 </div>
60</div>
61<script src="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/prism.min.js') }}"></script>
62<script src="{{ asset('https://cdnjs.cloudflare.com/ajax/libs/prism/1.4.1/components/prism-bash.min.js') }}"></script>
63{% 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
index 00000000..2e7dbcab
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Developer/index.html.twig
@@ -0,0 +1,68 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{% trans %}Developer{% endtrans %}{% endblock %}
4
5{% block content %}
6<div class="row">
7 <div class="col s12">
8 <div class="card-panel settings">
9
10 <div class="row">
11 <h3>{% trans %}Welcome to the wallabag API{% endtrans %}</h3>
12
13 <h4>{% trans %}Documentation{% endtrans %}</h4>
14
15 <ul>
16 <li><a href="{{ path('developer_howto_firstapp') }}">{% trans %}How to create my first application{% endtrans %}</a></li>
17 <li><a href="{{ path('nelmio_api_doc_index') }}">{% trans %}View full API documentation{% endtrans %}</a></li>
18 </ul>
19
20 <h4>{% trans %}Clients{% endtrans %}</h4>
21 <ul>
22 <li><a href="{{ path('developer_create_client') }}">{% trans %}Create a new client{% endtrans %}</a></li>
23 </ul>
24
25 <h4>{% trans %}Existing clients{% endtrans %}</h4>
26 {% if clients %}
27 <ul class="collapsible" data-collapsible="expandable">
28 {% for client in clients %}
29 <li>
30 <div class="collapsible-header">#{{ client.id }}</div>
31 <div class="collapsible-body">
32 <table class="striped">
33 <tr>
34 <td>{% trans %}Client ID{% endtrans %}</td>
35 <td><strong><code>{{ client.id }}_{{ client.randomId }}</code></strong></td>
36 </tr>
37 <tr>
38 <td>{% trans %}Client secret{% endtrans %}</td>
39 <td><strong><code>{{ client.secret }}</code></strong></td>
40 </tr>
41 <tr>
42 <td>{% trans %}Redirect URIs{% endtrans %}</td>
43 <td><strong><code>{{ client.redirectUris|json_encode() }}</code></strong></td>
44 </tr>
45 <tr>
46 <td>{% trans %}Grant type allowed{% endtrans %}</td>
47 <td><strong><code>{{ client.allowedGrantTypes|json_encode() }}</code></strong></td>
48 </tr>
49 </table>
50 <p>
51 {% trans %}You have the ability to remove this client. This action is IRREVERSIBLE !{% endtrans %}<br/>
52 {% trans %}If you remove it, every app configured with that client won't be able to auth on your wallabag.{% endtrans %}<br/>
53 <a class="waves-effect waves-light red btn" href="{{ path('developer_delete_client', {'id': client.id}) }}">{% trans %}Remove this client{% endtrans %}</a>
54 </p>
55 </div>
56 </li>
57 {% endfor %}
58 </ul>
59 {% else %}
60 {% trans %}No client yet.{% endtrans %}
61 {% endif %}
62 </div>
63
64 </div>
65 </div>
66</div>
67
68{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig
index 3d21271a..dea4242b 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Static/quickstart.html.twig
@@ -41,6 +41,10 @@
41 <li><a href="{{ path('import_wallabag_v1') }}">{% trans %}Migrate from wallabag v1{% endtrans %}</a></li> 41 <li><a href="{{ path('import_wallabag_v1') }}">{% trans %}Migrate from wallabag v1{% endtrans %}</a></li>
42 <li><a href="{{ path('import_wallabag_v2') }}">{% trans %}Migrate from wallabag v2{% endtrans %}</a></li> 42 <li><a href="{{ path('import_wallabag_v2') }}">{% trans %}Migrate from wallabag v2{% endtrans %}</a></li>
43 </ul> 43 </ul>
44 <h4>{% trans %}Developers{% endtrans %}</h4>
45 <ul>
46 <li><a href="{{ path('developer') }}">{% trans %}Create your third application{% endtrans %}</a></li>
47 </ul>
44 <h4>{% trans %}Full documentation{% endtrans %}</h4> 48 <h4>{% trans %}Full documentation{% endtrans %}</h4>
45 <ul> 49 <ul>
46 <li><a href="http://wallabag.readthedocs.org">{% trans %}Annotate your article{% endtrans %}</a></li> 50 <li><a href="http://wallabag.readthedocs.org">{% trans %}Annotate your article{% endtrans %}</a></li>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
index d7bfa7ae..f5d03084 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
@@ -50,6 +50,7 @@
50 {% endif %} 50 {% endif %}
51 <li class="bold {% if currentRoute == 'import' %}active{% endif %}"><a class="waves-effect" href="{{ path('import') }}">{% trans %}import{% endtrans %}</a></li> 51 <li class="bold {% if currentRoute == 'import' %}active{% endif %}"><a class="waves-effect" href="{{ path('import') }}">{% trans %}import{% endtrans %}</a></li>
52 <li class="bold {% if currentRoute == 'howto' %}active{% endif %}"><a class="waves-effect" href="{{ path('howto') }}">{% trans %}howto{% endtrans %}</a></li> 52 <li class="bold {% if currentRoute == 'howto' %}active{% endif %}"><a class="waves-effect" href="{{ path('howto') }}">{% trans %}howto{% endtrans %}</a></li>
53 <li class="bold {% if currentRoute == 'developer' %}active{% endif %}"><a class="waves-effect" href="{{ path('developer') }}">{% trans %}Developer{% endtrans %}</a></li>
53 <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> 54 <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>
54 </ul> 55 </ul>
55 <div class="nav-wrapper nav-panels"> 56 <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
index 00000000..fc220b85
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Tests/Controller/DeveloperControllerTest.php
@@ -0,0 +1,71 @@
1<?php
2
3namespace Wallabag\CoreBundle\Tests\Controller;
4
5use Wallabag\CoreBundle\Tests\WallabagCoreTestCase;
6
7class DeveloperControllerTest extends WallabagCoreTestCase
8{
9 public function testCreateClient()
10 {
11 $this->logInAs('admin');
12 $client = $this->getClient();
13 $em = $client->getContainer()->get('doctrine.orm.entity_manager');
14 $nbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
15
16 $crawler = $client->request('GET', '/developer/client/create');
17 $this->assertEquals(200, $client->getResponse()->getStatusCode());
18
19 $form = $crawler->filter('button[type=submit]')->form();
20
21 $client->submit($form);
22
23 $this->assertEquals(200, $client->getResponse()->getStatusCode());
24
25 $newNbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
26 $this->assertGreaterThan(count($nbClients), count($newNbClients));
27 }
28
29 public function testListingClient()
30 {
31 $this->logInAs('admin');
32 $client = $this->getClient();
33 $em = $client->getContainer()->get('doctrine.orm.entity_manager');
34 $nbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
35
36 $crawler = $client->request('GET', '/developer');
37 $this->assertEquals(200, $client->getResponse()->getStatusCode());
38 $this->assertEquals(count($nbClients), $crawler->filter('ul[class=collapsible] li')->count());
39 }
40
41 public function testDeveloperHowto()
42 {
43 $this->logInAs('admin');
44 $client = $this->getClient();
45
46 $crawler = $client->request('GET', '/developer/howto/first-app');
47 $this->assertEquals(200, $client->getResponse()->getStatusCode());
48 }
49
50 public function testRemoveClient()
51 {
52 $this->logInAs('admin');
53 $client = $this->getClient();
54 $em = $client->getContainer()->get('doctrine.orm.entity_manager');
55 $nbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
56
57 $crawler = $client->request('GET', '/developer');
58
59 $link = $crawler
60 ->filter('div[class=collapsible-body] p a')
61 ->eq(0)
62 ->link()
63 ;
64
65 $client->click($link);
66 $this->assertEquals(302, $client->getResponse()->getStatusCode());
67
68 $newNbClients = $em->getRepository('WallabagApiBundle:Client')->findAll();
69 $this->assertGreaterThan(count($newNbClients), count($nbClients));
70 }
71}