Clients.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. <style scoped>
  2. .action-link {
  3. cursor: pointer;
  4. }
  5. </style>
  6. <template>
  7. <div>
  8. <div class="card card-default">
  9. <div class="card-header">
  10. <div style="display: flex; justify-content: space-between; align-items: center;">
  11. <span>
  12. OAuth Clients
  13. </span>
  14. <a class="action-link" tabindex="-1" @click="showCreateClientForm">
  15. Create New Client
  16. </a>
  17. </div>
  18. </div>
  19. <div class="card-body">
  20. <!-- Current Clients -->
  21. <p class="mb-0" v-if="clients.length === 0">
  22. You have not created any OAuth clients.
  23. </p>
  24. <table class="table table-borderless mb-0" v-if="clients.length > 0">
  25. <thead>
  26. <tr>
  27. <th>Client ID</th>
  28. <th>Name</th>
  29. <th>Secret</th>
  30. <th></th>
  31. <th></th>
  32. </tr>
  33. </thead>
  34. <tbody>
  35. <tr v-for="client in clients">
  36. <!-- ID -->
  37. <td style="vertical-align: middle;">
  38. {{ client.id }}
  39. </td>
  40. <!-- Name -->
  41. <td style="vertical-align: middle;">
  42. {{ client.name }}
  43. </td>
  44. <!-- Secret -->
  45. <td style="vertical-align: middle;">
  46. <code>{{ client.secret }}</code>
  47. </td>
  48. <!-- Edit Button -->
  49. <td style="vertical-align: middle;">
  50. <a class="action-link" tabindex="-1" @click="edit(client)">
  51. Edit
  52. </a>
  53. </td>
  54. <!-- Delete Button -->
  55. <td style="vertical-align: middle;">
  56. <a class="action-link text-danger" @click="destroy(client)">
  57. Delete
  58. </a>
  59. </td>
  60. </tr>
  61. </tbody>
  62. </table>
  63. </div>
  64. </div>
  65. <!-- Create Client Modal -->
  66. <div class="modal fade" id="modal-create-client" tabindex="-1" role="dialog">
  67. <div class="modal-dialog">
  68. <div class="modal-content">
  69. <div class="modal-header">
  70. <h4 class="modal-title">
  71. Create Client
  72. </h4>
  73. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
  74. </div>
  75. <div class="modal-body">
  76. <!-- Form Errors -->
  77. <div class="alert alert-danger" v-if="createForm.errors.length > 0">
  78. <p class="mb-0"><strong>Whoops!</strong> Something went wrong!</p>
  79. <br>
  80. <ul>
  81. <li v-for="error in createForm.errors">
  82. {{ error }}
  83. </li>
  84. </ul>
  85. </div>
  86. <!-- Create Client Form -->
  87. <form role="form">
  88. <!-- Name -->
  89. <div class="form-group row">
  90. <label class="col-md-3 col-form-label">Name</label>
  91. <div class="col-md-9">
  92. <input id="create-client-name" type="text" class="form-control"
  93. @keyup.enter="store" v-model="createForm.name">
  94. <span class="form-text text-muted">
  95. Something your users will recognize and trust.
  96. </span>
  97. </div>
  98. </div>
  99. <!-- Redirect URL -->
  100. <div class="form-group row">
  101. <label class="col-md-3 col-form-label">Redirect URL</label>
  102. <div class="col-md-9">
  103. <input type="text" class="form-control" name="redirect"
  104. @keyup.enter="store" v-model="createForm.redirect">
  105. <span class="form-text text-muted">
  106. Your application's authorization callback URL.
  107. </span>
  108. </div>
  109. </div>
  110. <!-- Confidential -->
  111. <div class="form-group row">
  112. <label class="col-md-3 col-form-label">Confidential</label>
  113. <div class="col-md-9">
  114. <div class="checkbox">
  115. <label>
  116. <input type="checkbox" v-model="createForm.confidential">
  117. </label>
  118. </div>
  119. <span class="form-text text-muted">
  120. Require the client to authenticate with a secret. Confidential clients can hold credentials in a secure way without exposing them to unauthorized parties. Public applications, such as native desktop or JavaScript SPA applications, are unable to hold secrets securely.
  121. </span>
  122. </div>
  123. </div>
  124. </form>
  125. </div>
  126. <!-- Modal Actions -->
  127. <div class="modal-footer">
  128. <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
  129. <button type="button" class="btn btn-primary" @click="store">
  130. Create
  131. </button>
  132. </div>
  133. </div>
  134. </div>
  135. </div>
  136. <!-- Edit Client Modal -->
  137. <div class="modal fade" id="modal-edit-client" tabindex="-1" role="dialog">
  138. <div class="modal-dialog">
  139. <div class="modal-content">
  140. <div class="modal-header">
  141. <h4 class="modal-title">
  142. Edit Client
  143. </h4>
  144. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
  145. </div>
  146. <div class="modal-body">
  147. <!-- Form Errors -->
  148. <div class="alert alert-danger" v-if="editForm.errors.length > 0">
  149. <p class="mb-0"><strong>Whoops!</strong> Something went wrong!</p>
  150. <br>
  151. <ul>
  152. <li v-for="error in editForm.errors">
  153. {{ error }}
  154. </li>
  155. </ul>
  156. </div>
  157. <!-- Edit Client Form -->
  158. <form role="form">
  159. <!-- Name -->
  160. <div class="form-group row">
  161. <label class="col-md-3 col-form-label">Name</label>
  162. <div class="col-md-9">
  163. <input id="edit-client-name" type="text" class="form-control"
  164. @keyup.enter="update" v-model="editForm.name">
  165. <span class="form-text text-muted">
  166. Something your users will recognize and trust.
  167. </span>
  168. </div>
  169. </div>
  170. <!-- Redirect URL -->
  171. <div class="form-group row">
  172. <label class="col-md-3 col-form-label">Redirect URL</label>
  173. <div class="col-md-9">
  174. <input type="text" class="form-control" name="redirect"
  175. @keyup.enter="update" v-model="editForm.redirect">
  176. <span class="form-text text-muted">
  177. Your application's authorization callback URL.
  178. </span>
  179. </div>
  180. </div>
  181. </form>
  182. </div>
  183. <!-- Modal Actions -->
  184. <div class="modal-footer">
  185. <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
  186. <button type="button" class="btn btn-primary" @click="update">
  187. Save Changes
  188. </button>
  189. </div>
  190. </div>
  191. </div>
  192. </div>
  193. </div>
  194. </template>
  195. <script>
  196. export default {
  197. /*
  198. * The component's data.
  199. */
  200. data() {
  201. return {
  202. clients: [],
  203. createForm: {
  204. errors: [],
  205. name: '',
  206. redirect: '',
  207. confidential: true
  208. },
  209. editForm: {
  210. errors: [],
  211. name: '',
  212. redirect: ''
  213. }
  214. };
  215. },
  216. /**
  217. * Prepare the component (Vue 1.x).
  218. */
  219. ready() {
  220. this.prepareComponent();
  221. },
  222. /**
  223. * Prepare the component (Vue 2.x).
  224. */
  225. mounted() {
  226. this.prepareComponent();
  227. },
  228. methods: {
  229. /**
  230. * Prepare the component.
  231. */
  232. prepareComponent() {
  233. this.getClients();
  234. $('#modal-create-client').on('shown.bs.modal', () => {
  235. $('#create-client-name').focus();
  236. });
  237. $('#modal-edit-client').on('shown.bs.modal', () => {
  238. $('#edit-client-name').focus();
  239. });
  240. },
  241. /**
  242. * Get all of the OAuth clients for the user.
  243. */
  244. getClients() {
  245. axios.get('/oauth/clients')
  246. .then(response => {
  247. this.clients = response.data;
  248. });
  249. },
  250. /**
  251. * Show the form for creating new clients.
  252. */
  253. showCreateClientForm() {
  254. $('#modal-create-client').modal('show');
  255. },
  256. /**
  257. * Create a new OAuth client for the user.
  258. */
  259. store() {
  260. this.persistClient(
  261. 'post', '/oauth/clients',
  262. this.createForm, '#modal-create-client'
  263. );
  264. },
  265. /**
  266. * Edit the given client.
  267. */
  268. edit(client) {
  269. this.editForm.id = client.id;
  270. this.editForm.name = client.name;
  271. this.editForm.redirect = client.redirect;
  272. $('#modal-edit-client').modal('show');
  273. },
  274. /**
  275. * Update the client being edited.
  276. */
  277. update() {
  278. this.persistClient(
  279. 'put', '/oauth/clients/' + this.editForm.id,
  280. this.editForm, '#modal-edit-client'
  281. );
  282. },
  283. /**
  284. * Persist the client to storage using the given form.
  285. */
  286. persistClient(method, uri, form, modal) {
  287. form.errors = [];
  288. axios[method](uri, form)
  289. .then(response => {
  290. this.getClients();
  291. form.name = '';
  292. form.redirect = '';
  293. form.errors = [];
  294. $(modal).modal('hide');
  295. })
  296. .catch(error => {
  297. if (typeof error.response.data === 'object') {
  298. form.errors = _.flatten(_.toArray(error.response.data.errors));
  299. } else {
  300. form.errors = ['Something went wrong. Please try again.'];
  301. }
  302. });
  303. },
  304. /**
  305. * Destroy the given client.
  306. */
  307. destroy(client) {
  308. axios.delete('/oauth/clients/' + client.id)
  309. .then(response => {
  310. this.getClients();
  311. });
  312. }
  313. }
  314. }
  315. </script>