Browse Source

WIP services update

* page title service
* RPC service
Rafał Pitoń 10 years ago
parent
commit
6dd9031d5b
40 changed files with 315 additions and 202 deletions
  1. 5 5
      docs/developers/settings.rst
  2. 1 1
      misago/conf/defaults.py
  3. 1 1
      misago/conf/middleware.py
  4. 32 0
      misago/emberapp/app/adapters/application.js
  5. 2 3
      misago/emberapp/app/controllers/activation/request-link.js
  6. 5 2
      misago/emberapp/app/controllers/forgotten-password/change-form.js
  7. 1 1
      misago/emberapp/app/controllers/forgotten-password/request-link.js
  8. 0 4
      misago/emberapp/app/controllers/guest-nav.js
  9. 2 2
      misago/emberapp/app/controllers/login-modal.js
  10. 16 0
      misago/emberapp/app/initializers/rpc-service.js
  11. 10 0
      misago/emberapp/app/initializers/zxcvb-service.js
  12. 2 0
      misago/emberapp/app/router.js
  13. 1 2
      misago/emberapp/app/routes/activation/activate.js
  14. 7 0
      misago/emberapp/app/routes/application.js
  15. 1 2
      misago/emberapp/app/routes/forgotten-password/change-form.js
  16. 0 1
      misago/emberapp/app/routes/index.js
  17. 32 0
      misago/emberapp/app/routes/register.js
  18. 4 0
      misago/emberapp/app/services/page-title.js
  19. 52 0
      misago/emberapp/app/services/rpc.js
  20. 5 0
      misago/emberapp/app/services/zxcvb.js
  21. 6 6
      misago/emberapp/app/templates/activation/link-sent.hbs
  22. 1 1
      misago/emberapp/app/templates/error.hbs
  23. 6 6
      misago/emberapp/app/templates/forgotten-password/link-sent.hbs
  24. 1 1
      misago/emberapp/app/templates/guest-nav.hbs
  25. 1 0
      misago/emberapp/app/templates/register.hbs
  26. 15 0
      misago/emberapp/app/templates/register/closed.hbs
  27. 15 0
      misago/emberapp/app/templates/register/done.hbs
  28. 15 0
      misago/emberapp/app/templates/register/form.hbs
  29. 0 63
      misago/emberapp/app/utils/rpc.js
  30. 5 0
      misago/emberapp/config/environment.js
  31. 7 10
      misago/emberapp/tests/acceptance/forgotten-password-test.js
  32. 14 0
      misago/emberapp/tests/unit/routes/register-test.js
  33. 11 0
      misago/emberapp/tests/unit/services/page-title-test.js
  34. 18 0
      misago/emberapp/tests/unit/services/rpc-test.js
  35. 15 0
      misago/emberapp/tests/unit/services/zxcvb-test.js
  36. 1 5
      misago/emberapp/tests/unit/transforms/moment-date-test.js
  37. 0 79
      misago/emberapp/tests/unit/utils/rpc-test.js
  38. 1 1
      misago/emberapp/vendor/testutils/misago-preload-data.js
  39. 3 5
      misago/users/api/changepassword.py
  40. 1 1
      misago/users/migrations/0002_users_settings.py

+ 5 - 5
docs/developers/settings.rst

@@ -185,11 +185,6 @@ MISAGO_ATTACHMENTS_ROOT
 Path to directory that Misago should use to store post attachments. This directory shouldn't be accessible from outside world.
 
 
-MISAGO_AUTH_API_URL
--------------------
-Link name to API view used to validate sign-in credentials.
-
-
 MISAGO_AVATAR_SERVER_PATH
 -------------------------
 Url path that that all avatar server urls starts with. If you are running Misago subdirectory, make sure to update it (i.e. valid path for  "http://somesite.com/forums/" is ``/forums/user-avatar``).
@@ -258,6 +253,11 @@ MISAGO_HOURL_POST_LIMIT
 Hourly limit of posts that may be posted from single account. Fail-safe for situations when forum is flooded by spam bot. Change to 0 to lift this restriction.
 
 
+MISAGO_LOGIN_API_URL
+--------------------
+URL to API endpoint used to authenticate sign-in credentials. Musn't contain api prefix or wrapping slashes. Defaults to 'auth/login'.
+
+
 MISAGO_MAILER_BATCH_SIZE
 ------------------------
 

+ 1 - 1
misago/conf/defaults.py

@@ -252,7 +252,7 @@ MISAGO_STOP_FORUM_SPAM_MIN_CONFIDENCE = 80
 MISAGO_MAILER_BATCH_SIZE = 20
 
 # Auth paths
-MISAGO_AUTH_API_URL = 'misago:api:login'
+MISAGO_LOGIN_API_URL = 'auth/login'
 
 LOGIN_REDIRECT_URL = 'misago:index'
 LOGIN_URL = 'misago:login'

+ 1 - 1
misago/conf/middleware.py

@@ -6,7 +6,7 @@ class PreloadConfigMiddleware(object):
     def process_request(self, request):
         preloaded_settings = db_settings.get_public_settings()
         preloaded_settings.update({
-            'authApiUrl': reverse(settings.MISAGO_AUTH_API_URL),
+            'loginApiUrl': settings.MISAGO_LOGIN_API_URL,
 
             'loginRedirectUrl': reverse(settings.LOGIN_REDIRECT_URL),
             'loginUrl': reverse(settings.LOGIN_URL),

+ 32 - 0
misago/emberapp/app/adapters/application.js

@@ -0,0 +1,32 @@
+import Ember from 'ember';
+import DRFAdapter from './drf';
+import getCsrfToken from 'misago/utils/csrf';
+
+export default DRFAdapter.extend({
+  headers: function() {
+    return {
+      'X-CSRFToken': getCsrfToken()
+    };
+  }.property().volatile(),
+
+  // Simple ajax util for RPC requests
+  // raison d'etre: because default ones are processing server responses
+  // and there isn't response standard to allow that for RPC's
+  rpcAjax: function(url, data) {
+    var adapter = this;
+
+    return new Ember.RSVP.Promise(function(resolve, reject) {
+      var hash = adapter.ajaxOptions(url, 'POST', {data: data || null});
+
+      hash.success = function(json) {
+        Ember.run(null, resolve, json);
+      };
+
+      hash.error = function(jqXHR) {
+        Ember.run(null, reject, jqXHR);
+      };
+
+      Ember.$.ajax(hash);
+    }, 'DS: MisagoAdapter#rpc-ajax POST to ' + url);
+  }
+});

+ 2 - 3
misago/emberapp/app/controllers/activation/request-link.js

@@ -1,8 +1,7 @@
 import Ember from 'ember';
-import rpc from 'misago/utils/rpc';
 
 export default Ember.ObjectController.extend({
-  rpcUrl: 'activation/send-link/',
+  rpcUrl: 'activation/send-link',
   isLoading: false,
   email: '',
 
@@ -22,7 +21,7 @@ export default Ember.ObjectController.extend({
       this.set('isLoading', true);
 
       var self = this;
-      rpc(this.get('rpcUrl'), {
+      this.get('rpc').ajax(this.get('rpcUrl'), {
         email: email
       }).then(function(requestingUser) {
         self.send('success', requestingUser);

+ 5 - 2
misago/emberapp/app/controllers/forgotten-password/change-form.js

@@ -1,10 +1,13 @@
 import Ember from 'ember';
-import rpc from 'misago/utils/rpc';
 
 export default Ember.ObjectController.extend({
   isLoading: false,
   password: '',
 
+  change_password_url: function() {
+    return 'change-password/' + this.get('user_id') + '/' + this.get('token');
+  }.property('user_id', 'token'),
+
   actions: {
     submit: function() {
       if (this.get('isLoading')) {
@@ -21,7 +24,7 @@ export default Ember.ObjectController.extend({
       this.set('isLoading', true);
 
       var self = this;
-      rpc(this.get('change_password_url'), {
+      this.get('rpc').ajax(this.get('change_password_url'), {
         password: password
       }).then(function() {
         self.send('success');

+ 1 - 1
misago/emberapp/app/controllers/forgotten-password/request-link.js

@@ -1,5 +1,5 @@
 import RequestLinkController from 'misago/controllers/activation/request-link';
 
 export default RequestLinkController.extend({
-  rpcUrl: 'change-password/send-link/'
+  rpcUrl: 'change-password/send-link'
 });

+ 0 - 4
misago/emberapp/app/controllers/guest-nav.js

@@ -1,4 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
-});

+ 2 - 2
misago/emberapp/app/controllers/login-modal.js

@@ -1,5 +1,4 @@
 import Ember from 'ember';
-import rpc from 'misago/utils/rpc';
 import getCsrfToken from 'misago/utils/csrf';
 
 export default Ember.Controller.extend({
@@ -57,7 +56,7 @@ export default Ember.Controller.extend({
       }
 
       var self = this;
-      rpc(this.get('settings.authApiUrl'), credentials
+      this.get('rpc').ajax(this.get('settings.loginApiUrl'), credentials
       ).then(function() {
         self.send('success', credentials);
       }, function(jqXHR) {
@@ -99,6 +98,7 @@ export default Ember.Controller.extend({
       } else {
         this.get('toast').error(rejection.detail);
       }
+      return false;
     },
 
     // Go-to links

+ 16 - 0
misago/emberapp/app/initializers/rpc-service.js

@@ -0,0 +1,16 @@
+import RpcService from 'misago/services/rpc';
+
+export function initialize(_container, application) {
+  application.register('service:rpc', RpcService, { singleton: true });
+
+  application.inject('service:rpc', 'store', 'store:main');
+
+  [ 'route', 'controller' ].forEach((factory) => {
+    application.inject(factory, 'rpc', 'service:rpc');
+  });
+}
+
+export default {
+  name: 'rpc-service',
+  initialize: initialize
+};

+ 10 - 0
misago/emberapp/app/initializers/zxcvb-service.js

@@ -0,0 +1,10 @@
+import ZxcvbService from 'misago/services/zxcvb';
+
+export function initialize(container, application) {
+  application.register('service:zxcvb', ZxcvbService, { singleton: true });
+}
+
+export default {
+  name: 'zxcvb-service',
+  initialize: initialize
+};

+ 2 - 0
misago/emberapp/app/router.js

@@ -14,6 +14,7 @@ Router.map(function() {
   this.route('forgotten-password', { path: 'forgotten-password/' }, function() {
     this.route('change-form', { path: ':user_id/:token/' });
   });
+  this.route('register', { path: 'register/' });
 
   // Legal
 
@@ -27,6 +28,7 @@ Router.map(function() {
   this.route('error-404', { path: 'error-404/' });
   this.route('error-banned', { path: 'banned/:reason/' });
   this.route('not-found', { path: '*path' });
+  this.route('register');
 });
 
 export default Router;

+ 1 - 2
misago/emberapp/app/routes/activation/activate.js

@@ -1,10 +1,9 @@
 import Ember from 'ember';
 import ResetScroll from 'misago/mixins/reset-scroll';
-import rpc from 'misago/utils/rpc';
 
 export default Ember.Route.extend(ResetScroll, {
   model: function(params) {
-    return rpc('activation/' + params.user_id + '/' + params.token + '/validate-token/');
+    return this.get('rpc').ajax('activation/' + params.user_id + '/' + params.token + '/validate-token');
   },
 
   afterModel: function(model) {

+ 7 - 0
misago/emberapp/app/routes/application.js

@@ -2,6 +2,13 @@ import Ember from 'ember';
 
 export default Ember.Route.extend({
   actions: {
+    // Loading handler
+
+    loading: function() {
+      this.get('page-title').setPlaceholderTitle();
+      return true;
+    },
+
     // Error handlers
 
     error: function(reason) {

+ 1 - 2
misago/emberapp/app/routes/forgotten-password/change-form.js

@@ -1,10 +1,9 @@
 import Ember from 'ember';
 import ResetScroll from 'misago/mixins/reset-scroll';
-import rpc from 'misago/utils/rpc';
 
 export default Ember.Route.extend(ResetScroll, {
   model: function(params) {
-    return rpc('change-password/' + params.user_id + '/' + params.token + '/validate-token/');
+    return this.get('rpc').ajax('change-password/' + params.user_id + '/' + params.token + '/validate-token');
   },
 
   actions: {

+ 0 - 1
misago/emberapp/app/routes/index.js

@@ -4,7 +4,6 @@ import ResetScroll from 'misago/mixins/reset-scroll';
 export default Ember.Route.extend(ResetScroll, {
   actions: {
     didTransition: function() {
-      console.log(this.get('page-title'));
       this.get('page-title').setIndexTitle();
     }
   }

+ 32 - 0
misago/emberapp/app/routes/register.js

@@ -0,0 +1,32 @@
+import Ember from 'ember';
+import ResetScroll from 'misago/mixins/reset-scroll';
+
+export default Ember.Route.extend(ResetScroll, {
+  stage: 'form',
+
+  isForm: Ember.computed.equal('stage', 'form'),
+  isDone: Ember.computed.equal('stage', 'done'),
+  isClosed: Ember.computed.equal('stage', 'closed'),
+
+  resolveStage: function() {
+    if (!this.get('isDone') && this.get('settings.account_activation') === 'closed') {
+      // we didn't complete prior registration and registrations aren't open
+      this.set('stage', 'closed');
+    }
+  },
+
+  stageTemplate: function() {
+    return 'register.' + this.get('stage');
+  }.property('stage'),
+
+  renderTemplate: function() {
+    this.resolveStage();
+    this.render(this.get('stageTemplate'));
+  },
+
+  actions: {
+    didTransition: function() {
+      this.get('page-title').setTitle(gettext("Register"));
+    }
+  }
+});

+ 4 - 0
misago/emberapp/app/services/page-title.js

@@ -29,6 +29,10 @@ export default Ember.Service.extend({
     document.title = complete_title;
   },
 
+  setPlaceholderTitle: function() {
+    document.title = this.get('forumName');
+  },
+
   setIndexTitle: function() {
     document.title = this.get('indexTitle') || this.get('forumName');
   }

+ 52 - 0
misago/emberapp/app/services/rpc.js

@@ -0,0 +1,52 @@
+import Ember from 'ember';
+
+export default Ember.Object.extend({
+  ajax: function(recordOrProcedure, dataOrProcedure, data) {
+    // receive args
+    var record = null;
+    var procedure = null;
+
+    if (arguments.length === 3) {
+      record = recordOrProcedure;
+      procedure = dataOrProcedure;
+    } else {
+      procedure = recordOrProcedure;
+      data = dataOrProcedure;
+    }
+
+    // get adapter to be used for RPC
+    // note: in case of Model being null this cheats adapterFor to return
+    // 'adapter:application'. we are doing this, because for some reason
+    // store.defaultAdapter fails to return django adapter
+    var adapter = this.get('store').adapterFor(record || {typeKey: 'application'});
+
+    // build api call URL
+    var url = null;
+    if (record) {
+      url = this.buildRecordProcedureURL(adapter, record, procedure);
+    } else {
+      url = this.buildProcedureURL(adapter, procedure);
+    }
+
+    // return RPC promise
+    return adapter.rpcAjax(url, data || null);
+  },
+
+  buildRecordProcedureURL: function(adapter, record, procedure) {
+    var url = adapter.buildURL(record.typeKey, record.id, record);
+    return url + '/' + Ember.String.camelize(procedure);
+  },
+
+  buildProcedureURL: function(adapter, procedure) {
+    var url = adapter.buildURL(procedure);
+    return this.unpluralizeUrlProcedure(url, procedure);
+  },
+
+  unpluralizeUrlProcedure: function(url, procedure) {
+    // decamelize name and reverse path pluralization for type for procedure
+    var decamelized = Ember.String.decamelize(procedure);
+    var pluralized = Ember.String.pluralize(decamelized);
+
+    return url.replace(pluralized, decamelized);
+  }
+});

+ 5 - 0
misago/emberapp/app/services/zxcvb.js

@@ -0,0 +1,5 @@
+import Ember from 'ember';
+
+export default Ember.Service.extend({
+
+});

+ 6 - 6
misago/emberapp/app/templates/activation/link-sent.hbs

@@ -7,13 +7,13 @@
 
   <div class="container">
 
-  <p class="lead">
-    {{gettext "%(username)s, we have sent your activation link to %(email)s." username=username email=email}}
-  </p>
+    <p class="lead">
+      {{gettext "%(username)s, we have sent your activation link to %(email)s." username=username email=email}}
+    </p>
 
-  <button class="btn btn-default" {{action "retry"}}>
-    {{gettext "Try again?"}}
-  </button>
+    <button class="btn btn-default" {{action "retry"}}>
+      {{gettext "Try again?"}}
+    </button>
 
   </div>
 </div>

+ 1 - 1
misago/emberapp/app/templates/error.hbs

@@ -7,7 +7,7 @@
       </div>
 
       <div class="error-message">
-        <p class="lead">{{gettext "Server has errored."}}</p>
+        <p class="lead">{{gettext "Application error has errored."}}</p>
       </div>
 
     </div>

+ 6 - 6
misago/emberapp/app/templates/forgotten-password/link-sent.hbs

@@ -7,13 +7,13 @@
 
   <div class="container">
 
-  <p class="lead">
-    {{gettext "%(username)s, we have sent link to your password change form to %(email)s." username=username email=email}}
-  </p>
+    <p class="lead">
+      {{gettext "%(username)s, we have sent link to your password change form to %(email)s." username=username email=email}}
+    </p>
 
-  <button class="btn btn-default" {{action "retry"}}>
-    {{gettext "Try again?"}}
-  </button>
+    <button class="btn btn-default" {{action "retry"}}>
+      {{gettext "Try again?"}}
+    </button>
 
   </div>
 </div>

+ 1 - 1
misago/emberapp/app/templates/guest-nav.hbs

@@ -3,7 +3,7 @@
     {{gettext "Sign in"}}
   </button>
 
-  <button type="button" class="btn btn-info btn-logout navbar-btn btn-sm">
+  <button type="button" class="btn btn-info btn-logout navbar-btn btn-sm" {{action "register"}}>
     {{gettext "Join now"}}
   </button>
 </div>

+ 1 - 0
misago/emberapp/app/templates/register.hbs

@@ -0,0 +1 @@
+{{outlet}}

+ 15 - 0
misago/emberapp/app/templates/register/closed.hbs

@@ -0,0 +1,15 @@
+<div class="register-closed-page">
+  <div class="page-header">
+    <div class="container">
+      <h1>{{gettext "Register account"}}</h1>
+    </div>
+  </div>
+
+  <div class="container">
+
+    <p class="lead">
+      {{gettext "New member registrations are not currently accepted."}}
+    </p>
+
+  </div>
+</div>

+ 15 - 0
misago/emberapp/app/templates/register/done.hbs

@@ -0,0 +1,15 @@
+<div class="register-done-page">
+  <div class="page-header">
+    <div class="container">
+      <h1>{{gettext "Register account"}}</h1>
+    </div>
+  </div>
+
+  <div class="container">
+
+    <p class="lead">
+      WIP "what after registration?" page.
+    </p>
+
+  </div>
+</div>

+ 15 - 0
misago/emberapp/app/templates/register/form.hbs

@@ -0,0 +1,15 @@
+<div class="register-form-page">
+  <div class="page-header">
+    <div class="container">
+      <h1>{{gettext "Register account"}}</h1>
+    </div>
+  </div>
+
+  <div class="container">
+
+    <p class="lead">
+      WIP Register form template
+    </p>
+
+  </div>
+</div>

+ 0 - 63
misago/emberapp/app/utils/rpc.js

@@ -1,63 +0,0 @@
-import Ember from 'ember';
-import getCsrfToken from 'misago/utils/csrf';
-import {startsWith, endsWith} from 'misago/utils/strings';
-import ENV from '../config/environment';
-
-export function buildUrl(procedure, config) {
-  if (typeof config === 'undefined') {
-    config = ENV.APP;
-  }
-
-  var finalUrl = config.API_HOST;
-
-  if (!startsWith(procedure, '/' + config.API_NAMESPACE + '/')) {
-    finalUrl += '/' + config.API_NAMESPACE + '/';
-  }
-
-  finalUrl += procedure;
-
-  if (config.API_ADD_TRAILING_SLASHES && !endsWith(finalUrl, '/')) {
-    finalUrl += '/';
-  }
-
-  return finalUrl;
-}
-
-export function ajax(url, data) {
-  return new Ember.RSVP.Promise(function(resolve, reject){
-    function success(json) {
-      Ember.run(null, resolve, json);
-    }
-
-    function error(jqXHR) {
-      if (jqXHR.status === 200) {
-        var data = {};
-        if (typeof jqXHR.responseJSON !== 'undefined') {
-          data = jqXHR.responseJSON;
-        }
-        Ember.run(null, resolve, data);
-      } else {
-        Ember.run(null, reject, jqXHR);
-      }
-    }
-
-    Ember.$.ajax(url, {
-      type: 'POST',
-      accepts: 'application/json',
-      contentType: 'application/json;charset=UTF-8',
-      data: JSON.stringify(data || {}),
-      dataType: 'json',
-
-      headers: {
-        'X-CSRFToken': getCsrfToken()
-      },
-
-      error: error,
-      success: success
-    });
-  }, 'RPC: ' + url);
-}
-
-export default function(procedure, data, config) {
-  return ajax(buildUrl(procedure, config), data);
-}

+ 5 - 0
misago/emberapp/config/environment.js

@@ -64,6 +64,11 @@ module.exports = function(environment) {
 
     ENV.APP.rootElement = '#ember-testing';
 
+    // Maintain api config
+    ENV.APP.API_HOST = '';
+    ENV.APP.API_NAMESPACE = 'api';
+    ENV.APP.API_ADD_TRAILING_SLASHES = true;
+
     // Reduce toast display times for test runner
     ENV.APP.TOAST_BASE_DISPLAY_TIME = 200;
     ENV.APP.TOAST_LENGTH_FACTOR = 0;

+ 7 - 10
misago/emberapp/tests/acceptance/forgotten-password-test.js

@@ -256,8 +256,7 @@ test('no new password is entered', function(assert) {
     status: 200,
     responseText: {
       'user_id': 1,
-      'token': 'token',
-      'change_password_url': '/api/change-password-url/'
+      'token': 'token'
     }
   });
 
@@ -278,14 +277,13 @@ test('new password is invalid', function(assert) {
     status: 200,
     responseText: {
       'user_id': 1,
-      'token': 'token',
-      'change_password_url': '/api/change-password-url/'
+      'token': 'token'
     }
   });
 
   var message = 'Entered password is not allowed.';
   Ember.$.mockjax({
-    url: '/api/change-password-url/',
+    url: '/api/change-password/1/token/',
     status: 400,
     responseText: {
       'detail': message
@@ -310,15 +308,14 @@ test('new password is accepted', function(assert) {
     status: 200,
     responseText: {
       'user_id': 1,
-      'token': 'token',
-      'change_password_url': '/api/change-password-url/'
+      'token': 'token'
     }
   });
 
-  var message = 'lul';
   Ember.$.mockjax({
-    url: '/api/change-password-url/',
-    status: 200
+    url: '/api/change-password/1/token/',
+    status: 200,
+    responseText: {'detail': 'ok'}
   });
 
   visit('/forgotten-password/1/token/');

+ 14 - 0
misago/emberapp/tests/unit/routes/register-test.js

@@ -0,0 +1,14 @@
+import {
+  moduleFor,
+  test
+} from 'ember-qunit';
+
+moduleFor('route:register', {
+  // Specify the other units that are required for this test.
+  // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+  var route = this.subject();
+  assert.ok(route);
+});

+ 11 - 0
misago/emberapp/tests/unit/services/page-title-test.js

@@ -39,6 +39,17 @@ test('setTitle changes document title', function(assert) {
   assert.equal(document.title, 'Test Thread (page 12) | Support | Test Forum');
 });
 
+test('setPlaceholderTitle changes document title to one defined for index', function(assert) {
+  assert.expect(1);
+
+  var service = this.subject();
+  service.set('forumName', 'Placeholder Test Forum');
+
+  // no index title is set
+  service.setPlaceholderTitle();
+  assert.equal(document.title, 'Placeholder Test Forum');
+});
+
 test('setIndexTitle changes document title to one defined for index', function(assert) {
   assert.expect(2);
 

+ 18 - 0
misago/emberapp/tests/unit/services/rpc-test.js

@@ -0,0 +1,18 @@
+import {
+  moduleFor,
+  test
+} from 'ember-qunit';
+
+moduleFor('service:rpc');
+
+test('unpluralizeUrlProcedure fixes urls', function(assert) {
+  assert.expect(2);
+
+  var service = this.subject();
+
+  var url = service.unpluralizeUrlProcedure('/some-words/', 'some-word');
+  assert.equal(url, '/some-word/');
+
+  url = service.unpluralizeUrlProcedure('/model/some-words/', 'some-word');
+  assert.equal(url, '/model/some-word/');
+});

+ 15 - 0
misago/emberapp/tests/unit/services/zxcvb-test.js

@@ -0,0 +1,15 @@
+import {
+  moduleFor,
+  test
+} from 'ember-qunit';
+
+moduleFor('service:zxcvb', {
+  // Specify the other units that are required for this test.
+  // needs: ['service:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+  var service = this.subject();
+  assert.ok(service);
+});

+ 1 - 5
misago/emberapp/tests/unit/transforms/moment-date-test.js

@@ -3,12 +3,8 @@ import {
   test
 } from 'ember-qunit';
 
-moduleFor('transform:moment-date', {
-  // Specify the other units that are required for this test.
-  // needs: ['serializer:foo']
-});
+moduleFor('transform:moment-date');
 
-// Replace this with your real tests.
 test('it exists', function(assert) {
   var transform = this.subject();
   assert.ok(transform);

+ 0 - 79
misago/emberapp/tests/unit/utils/rpc-test.js

@@ -1,79 +0,0 @@
-import Ember from 'ember';
-import { default as rpc, buildUrl, ajax } from '../../../utils/rpc';
-import { module, test } from 'qunit';
-
-module('RPC', {
-  afterEach: function() {
-    Ember.$.mockjax.clear();
-  }
-});
-
-test('buildUrl builds valid urls', function(assert) {
-  assert.expect(3);
-
-  assert.equal(buildUrl('some/procedure', {
-    API_HOST: '',
-    API_NAMESPACE: 'api/v2',
-    API_ADD_TRAILING_SLASHES: true
-  }), '/api/v2/some/procedure/');
-
-  assert.equal(buildUrl('some/procedure', {
-    API_HOST: '',
-    API_NAMESPACE: 'api/v2',
-    API_ADD_TRAILING_SLASHES: false
-  }), '/api/v2/some/procedure');
-
-  assert.equal(buildUrl('some/procedure', {
-    API_HOST: 'https://api.testsite.com',
-    API_NAMESPACE: 'api/v2',
-    API_ADD_TRAILING_SLASHES: false
-  }), 'https://api.testsite.com/api/v2/some/procedure');
-});
-
-var conf = {
-  API_HOST: '',
-  API_NAMESPACE: 'api',
-  API_ADD_TRAILING_SLASHES: true
-};
-
-test('successfull rpc call passes', function(assert) {
-  assert.expect(1);
-  var done = assert.async();
-
-  Ember.$.mockjax({
-    url: "/api/some-rpc/",
-    status: 200,
-    responseText: {
-      'detail': 'it works'
-    }
-  });
-
-  rpc('some-rpc', {}, conf).then(function(data) {
-    assert.equal(data.detail, 'it works');
-  }, function() {
-    assert.fail("rpc call should pass");
-  }).finally(function() {
-    done();
-  });
-});
-
-test('invalid rpc call fails', function(assert) {
-  assert.expect(1);
-  var done = assert.async();
-
-  Ember.$.mockjax({
-    url: "/api/some-rpc/",
-    status: 400,
-    responseText: {
-      'detail': 'nope'
-    }
-  });
-
-  rpc('some-rpc', {}, conf).then(function() {
-    assert.fail("rpc call should fail");
-  }, function(jqXHR) {
-    assert.equal(jqXHR.responseJSON.detail, 'nope');
-  }).finally(function() {
-    done();
-  });
-});

+ 1 - 1
misago/emberapp/vendor/testutils/misago-preload-data.js

@@ -17,7 +17,7 @@ window.MisagoData = {
     "privacy_policy_title": "Polityka prywatno\u015bci",
     "privacy_policy": true,
 
-    "authApiUrl": "/api/auth/login/",
+    "loginApiUrl": "auth/login",
 
     "loginUrl": "/login/",
     "loginRedirectUrl": "/",

+ 3 - 5
misago/users/api/changepassword.py

@@ -81,10 +81,8 @@ def send_link(request):
 @password_api_view
 def validate_token(request, user, token):
     return Response({
-        'change_password_url': reverse('misago:api:change_password', kwargs={
-            'user_id': user.id,
-            'token': token,
-        }),
+        'user_id': user.id,
+        'token': token,
         'username': user.username
     })
 
@@ -101,4 +99,4 @@ def change_password(request, user, token):
         return Response({'detail': e.messages[0]},
                         status=status.HTTP_400_BAD_REQUEST)
 
-    return Response()
+    return Response({'detail': 'ok'})

+ 1 - 1
misago/users/migrations/0002_users_settings.py

@@ -27,7 +27,7 @@ def create_users_settings_group(apps, schema_editor):
                             ('none', _("No activation required")),
                             ('user', _("Activation Token sent to User")),
                             ('admin', _("Activation by Administrator")),
-                            ('disabled', _("Don't allow new registrations"))
+                            ('closed', _("Don't allow new registrations"))
                         )
                     },
                     'is_public': True,