Browse Source

active users list in ember.js

Rafał Pitoń 9 years ago
parent
commit
0761e49826

+ 4 - 1
misago/emberapp/app/mixins/shared-user-attrs.js

@@ -8,8 +8,11 @@ export default Ember.Mixin.create(WithUrlName, {
   avatar_hash: DS.attr('string'),
   title: DS.attr('string'),
   rank: DS.attr('ember-object'),
-  state: DS.attr('ember-object'),
+  threads: DS.attr('number'),
+  posts: DS.attr('number'),
   signature: DS.attr('string'),
+  state: DS.attr('ember-object'),
+  meta: DS.attr('ember-object'),
 
   finalTitle: function() {
     if (this.get('title')) {

+ 5 - 1
misago/emberapp/app/routes/users.js

@@ -9,5 +9,9 @@ export default MisagoRoute.extend({
 
   model: function() {
     return this.store.find('rank');
-  }
+  },
+
+  unloadUsers: function() {
+    this.store.unloadAll('user');
+  }.on('deactivate')
 });

+ 21 - 3
misago/emberapp/app/routes/users/active.js

@@ -1,9 +1,27 @@
 import MisagoRoute from 'misago/routes/misago';
 
 export default MisagoRoute.extend({
-  model: function(params) {
-    console.log(params);
-    return { val: 'nope' };
+  beforeModel: function() {
+    this.store.unloadAll('user');
+  },
+
+  model: function() {
+    return this.store.find('user', {
+      'list': 'active'
+    });
+  },
+
+  afterModel: function(users) {
+    users.forEach(function(model, index) {
+      model.set('meta.ranking', index + 1);
+    });
+  },
+
+  setupController: function(controller, model) {
+    this.controllerFor('users.active').setProperties({
+      'model': model,
+      'meta': model.get('meta')
+    });
   },
 
   actions: {

+ 10 - 0
misago/emberapp/app/routes/users/online.js

@@ -1,6 +1,16 @@
 import MisagoRoute from 'misago/routes/misago';
 
 export default MisagoRoute.extend({
+  beforeModel: function() {
+    this.store.unloadAll('user');
+  },
+
+  model: function() {
+    return this.store.find('user', {
+      'list': 'online'
+    });
+  },
+
   actions: {
     didTransition: function() {
       this.set('title', {

+ 1 - 5
misago/emberapp/app/routes/users/rank.js

@@ -14,9 +14,5 @@ export default MisagoRoute.extend({
     if (!model.get('is_tab')) {
       this.throw404();
     }
-  },
-
-  unloadRankUsers: function() {
-    this.store.unloadAll('user');
-  }.on('deactivate')
+  }
 });

+ 1 - 0
misago/emberapp/app/styles/misago/misago.less

@@ -14,6 +14,7 @@
 @import "navs.less";
 @import "pagination.less";
 @import "page-header.less";
+@import "tables.less";
 @import "typo.less";
 @import "list-groups.less";
 @import "misc.less";

+ 78 - 0
misago/emberapp/app/styles/misago/tables.less

@@ -0,0 +1,78 @@
+//
+// Tables
+// --------------------------------------------------
+
+
+// Shared table styles
+.panel.panel-table {
+  border: none;
+  border-radius: @border-radius-base;
+  .shadow-2dp();
+
+  &>table {
+    thead tr th {
+      border-bottom-width: 1px;
+
+      font-size: @font-size-small;
+    }
+
+    &, tr, td {
+      background: none;
+    }
+
+    tr:last-child td {
+      border-bottom: none;
+    }
+
+    &.vertically-aligned {
+      thead, tbody {
+        & tr>* {
+          vertical-align: middle;
+        }
+      }
+    }
+  }
+}
+
+
+// Users table
+.panel.panel-table.users-table {
+  &>table {
+    tbody tr {
+      td {
+        font-size: @font-size-large;
+        font-weight: @weight-light;
+      }
+
+      .col-avatar {
+        width: 1%;
+
+        img {
+          border-radius: @avatar-radius;
+
+          // Make avatar less dominating on larger displays
+          @media (min-width: @screen-md-min) {
+            border-radius: @avatar-radius-small;
+            padding-right: 0px;
+
+            width: 32px;
+            height: 32px;
+          }
+        }
+      }
+
+      .col-username {
+        a, a:link, a:visited, a:focus, a:hover {
+          color: @site-link-active-color;
+          font-weight: normal;
+        }
+
+        p {
+          margin: 0px;
+
+          font-size: @font-size-small;
+        }
+      }
+    }
+  }
+}

+ 50 - 1
misago/emberapp/app/templates/users/active.hbs

@@ -1 +1,50 @@
-Active users!
+{{#if model.length}}
+  <p class="lead">
+    {{ngettext "%(users)s user has posted new messages in last %(days)s days." "%(users)s users have posted new messages in last %(days)s days." model.length users=model.length days=meta.ranking_length}}
+  </p>
+
+  <div class="panel panel-table users-table">
+    <table class="table vertically-aligned">
+      <thead class="hidden-xs hidden-sm">
+        <tr>
+          <th colspan="2">{{gettext "User"}}</th>
+          <th>{{gettext "Position"}}</th>
+          <th>{{gettext "Posts"}}</th>
+          <th>{{gettext "Total"}}</th>
+        </tr>
+      </thead>
+      <tbody>
+        {{#each model as |user|}}
+          <tr>
+            <td class="col-avatar">
+              {{#link-to 'user' user.url_name}}
+                {{user-avatar user=user size=50}}
+              {{/link-to}}
+            </td>
+            <td class="col-username">
+              {{#link-to 'user' user.url_name}}
+                {{user.username}}
+              {{/link-to}}
+              <p class="hidden-md hidden-lg">
+                {{ngettext "#%(rank)s with %(score)s post and %(total)s total." "#%(rank)s with %(score)s posts and %(total)s total." user.meta.score rank=user.meta.ranking score=user.meta.score total=user.posts}}
+              </p>
+            </td>
+            <td class="hidden-xs hidden-sm">
+              #{{user.meta.ranking}}
+            </td>
+            <td class="hidden-xs hidden-sm">
+              {{user.meta.score}}
+            </td>
+            <td class="hidden-xs hidden-sm">
+              {{user.posts}}
+            </td>
+          </tr>
+        {{/each}}
+      </tbody>
+    </table>
+  </div>
+{{else}}
+  <p class="lead">
+    {{gettext "No users have posted during last %(days)s days." days=meta.ranking_length}}
+  </p>
+{{/if}}

+ 7 - 2
misago/users/api/userendpoints/list.py

@@ -44,7 +44,12 @@ def real_active():
     for result in queryset[:settings.MISAGO_RANKING_SIZE]:
         result.score = result.num_posts
         users_ranking.append(result)
-    return {'data': ScoredUserSerializer(users_ranking, many=True).data}
+    return {
+        'results': ScoredUserSerializer(users_ranking, many=True).data,
+        'meta': {
+            'ranking_length': settings.MISAGO_RANKING_LENGTH
+        }
+    }
 
 
 def online(request, queryset):
@@ -67,7 +72,7 @@ def real_online(request):
         result.user.last_click = result.last_click
         users_online.append(result.user)
 
-    return {'data': OnlineUserSerializer(users_online, many=True).data}
+    return {'results': OnlineUserSerializer(users_online, many=True).data}
 
 
 def rank(request, queryset):

+ 9 - 2
misago/users/api/users.py

@@ -64,8 +64,15 @@ class UserViewSet(viewsets.GenericViewSet):
         if not users_list:
             return Response([])
 
-        if 'data' in users_list:
-            return Response(users_list['data'])
+        if 'results' in users_list:
+            if 'meta' in users_list:
+                response_json = {
+                    'results': users_list['results']
+                }
+                response_json.update(users_list['meta'])
+                return Response(response_json)
+            else:
+                return Response(users_list['results'])
 
         if users_list.get('paginate'):
             page = self.paginate_queryset(users_list['queryset'])

+ 15 - 7
misago/users/serializers/user.py

@@ -84,8 +84,10 @@ class UserSerializer(serializers.ModelSerializer):
             'avatar_hash',
             'title',
             'rank',
-            'state',
             'signature',
+            'threads',
+            'posts',
+            'state',
         )
 
     def get_state(self, obj):
@@ -113,8 +115,10 @@ class OnlineUserSerializer(UserSerializer):
             'avatar_hash',
             'title',
             'rank',
-            'last_click',
             'signature',
+            'threads',
+            'posts',
+            'last_click',
         )
 
     def get_last_click(self, obj):
@@ -122,7 +126,7 @@ class OnlineUserSerializer(UserSerializer):
 
 
 class ScoredUserSerializer(UserSerializer):
-    score = serializers.SerializerMethodField()
+    meta = serializers.SerializerMethodField()
 
     class Meta:
         model = get_user_model()
@@ -133,12 +137,14 @@ class ScoredUserSerializer(UserSerializer):
             'avatar_hash',
             'title',
             'rank',
-            'score',
             'signature',
+            'threads',
+            'posts',
+            'meta',
         )
 
-    def get_score(self, obj):
-        return obj.score
+    def get_meta(self, obj):
+        return {'score': obj.score}
 
 
 class UserProfileSerializer(UserSerializer):
@@ -158,8 +164,10 @@ class UserProfileSerializer(UserSerializer):
             'avatar_hash',
             'title',
             'rank',
-            'is_signature_locked',
             'signature',
+            'is_signature_locked',
+            'threads',
+            'posts',
             'is_followed',
             'is_blocked',
             'state',