Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

175 linhas
4.1 KiB

  1. // authentication model
  2. const _make_auth = api_root => {
  3. // members
  4. let _login_name = '', _password = ''
  5. let _token_payload = {}
  6. // methods
  7. let _token = value => {
  8. if (value) localStorage.setItem('token', value)
  9. return localStorage.getItem('token')
  10. }
  11. let _load_token_payload = _ => {
  12. try {
  13. _token_payload = JSON.parse(atob(_token().split('.')[1]))
  14. } catch (e) {
  15. console.log('failed parsing token: ', e)
  16. }
  17. }
  18. let _login = _ => m.request({
  19. method: 'POST',
  20. url: `${api_root}/rpc/login`,
  21. body: {
  22. login_name: _login_name,
  23. password: _password
  24. }}).then(data => {
  25. _token(data)
  26. _load_token_payload()
  27. // TODO set to origin page
  28. m.route.set('/')
  29. }).catch(e => alert(e.response.message))
  30. // initialize
  31. _load_token_payload()
  32. // public methods
  33. return {
  34. login: _login,
  35. signed_in: _ => _token() ? true : false,
  36. payload: _ => _token_payload,
  37. token: _token,
  38. login_name: value => {
  39. if (value) _login_name = value
  40. return _login_name
  41. },
  42. password: value => {
  43. if (value) _password = value
  44. return _password
  45. }
  46. }
  47. }
  48. // main api
  49. const _make_api = (api_root, need_auth=true) => {
  50. // private state
  51. let _root = api_root
  52. // if auth is required
  53. let _auth = need_auth ? _make_auth(api_root) : null
  54. return {
  55. // utilities
  56. download: download,
  57. // expose authentication module
  58. auth: _auth,
  59. }
  60. }
  61. /* api wrapper */
  62. /*
  63. * api.request(options): all options will be forwarded to m.request, except a
  64. * few:
  65. *
  66. * 1. options.queries: an array of object '{label: <>, value: <>, op: <>}' to
  67. * build postgrest query easily
  68. */
  69. export default (api_root, auth={}) => {
  70. return {
  71. // wrap m.request with authentication validation if demanded
  72. request: (options = {}) => {
  73. /* normalize arguments */
  74. if (typeof options === 'string') {
  75. options = {url: options}
  76. }
  77. /* normalize url */
  78. if (options.url.startsWith('/'))
  79. options.url = api_root + options.url
  80. /* normalize headers */
  81. // 1. check if auth is required
  82. if (false/*need_auth*/) {
  83. // insert auth header if availible
  84. if (_auth.token()) {
  85. options.headers = {
  86. Authorization: 'Bearer ' + _auth.token(),
  87. ...options.headers
  88. }
  89. }
  90. // route to login
  91. else {
  92. m.route.set('/login')
  93. }
  94. }
  95. // 2. return values on Prefer
  96. // if (['POST', 'PATCH'].includes(options.method) && options.headers && !options.headers.Prefer)
  97. if (['POST', 'PATCH'].includes(options.method))
  98. options.config = xhr => {
  99. xhr.setRequestHeader('Prefer', 'return=representation')
  100. return xhr
  101. }
  102. // normalize params: since options.params is an object, it cannot support
  103. // duplicated query keys, while postgrest supports that.
  104. //
  105. // Simply build query string by hand.
  106. if (options.queries) {
  107. // build the query string
  108. let _query_string = options.queries
  109. .filter(query => typeof query != 'undefined')
  110. .map(query => {
  111. // prepare the query kv pair and optional operator
  112. let k = query.label
  113. let v = query.value
  114. let op = query.op
  115. // return early if v is empty
  116. if (typeof v == 'undefined' || (!v && v !== 0))
  117. return undefined
  118. // generate value if v is a function
  119. if (typeof v == 'function')
  120. v = v()
  121. // format v on k & op
  122. if (op == 'like')
  123. v = `*${v}*`
  124. else if (op == 'like.right') {
  125. v = `${v}*`
  126. op = 'like'
  127. } else if (op == 'in')
  128. v = `(${v.join(',')})`
  129. else if (k == 'and') {
  130. v = '(' + v.filter(sub_query => sub_query.value == 0 || sub_query.value).map(sub_query => `${sub_query.label}.${sub_query.op}.${typeof sub_query.value == 'function' ? sub_query.value() : sub_query.value}`).join(',') + ')'
  131. }
  132. return {k: k, v: op ? `${op}.${v}` : v}
  133. })
  134. .map(query => query.k + '=' + encodeURIComponent(query.v)).join('&')
  135. // append query string to url if necessary
  136. if (_query_string)
  137. options.url = options.url + '?' + _query_string
  138. delete options.queries
  139. }
  140. return m.request(options).catch(e => {
  141. if (e.code === 401) {
  142. localStorage.removeItem('token')
  143. m.route.set('/login')
  144. }
  145. throw e
  146. })
  147. }
  148. }
  149. }