UserProfile.js

From disqus.com, 7 Months ago, written in JavaScript, viewed 3 times. This paste is a reply to backboneUtils.js from disqus.com - view diff
URL https://pastebin.freepbx.org/view/22f8a16f Embed
Download Paste or View Raw
  1. define('home/models/UserProfile',[
  2.     'jquery',
  3.     'underscore',
  4.     'backbone',
  5.  
  6.     'home/utils/backboneUtils',
  7.  
  8.     'home/collections/PaginatedUserCollection',
  9.     'home/collections/FeedItemCollection',
  10.     'home/collections/FollowingForumCollection',
  11.     'home/collections/FollowingChannelCollection',
  12.     'home/collections/FollowingUserCollection',
  13.     'home/collections/MostActiveForumCollection',
  14.     'home/collections/UserManagedChannelCollection',
  15.  
  16.     'core/UniqueModel',
  17.     'home/models/User',
  18.     'home/models/Feed',
  19.     'home/models/UserModerationDetails',
  20.  
  21.     'core/api',
  22. ], function (
  23.     $,
  24.     _,
  25.     Backbone,
  26.  
  27.     backboneUtils,
  28.  
  29.     PaginatedUserCollection,
  30.     FeedItemCollection,
  31.     FollowingForumCollection,
  32.     FollowingChannelCollection,
  33.     FollowingUserCollection,
  34.     MostActiveForumCollection,
  35.     UserManagedChannelCollection,
  36.  
  37.     UniqueModel,
  38.     User,
  39.     Feed,
  40.     UserModerationDetails,
  41.  
  42.     api
  43. ) {
  44.     'use strict';
  45.  
  46.     var UserProfile = Backbone.Model.extend({
  47.         idAttribute: 'username',
  48.  
  49.         initialize: function (_attributes, options) {
  50.             this.initializeRelated(
  51.                 'user',
  52.                 _.defaults({
  53.                     user: { username: this.get('username') },
  54.                 }, options),
  55.                 User
  56.             );
  57.  
  58.             this.user.listenTo(this, 'change:username', this.updateUsername);
  59.             this.listenTo(this.user, 'change:isFollowing', this.updateFollowers);
  60.  
  61.             var userFetchString = 'username:' + this.user.get('username');
  62.             var fetchOptions = {
  63.                 user: userFetchString,
  64.                 order: 'desc',
  65.             };
  66.  
  67.             this.forumsFollowing = new Feed({
  68.                 fetchOptions: fetchOptions,
  69.             }, {
  70.                 collectionClass: FollowingForumCollection,
  71.             });
  72.  
  73.             // channelsFollowing is a list of channels that are followed directly because
  74.             // their primary forums cannot be followed (as opposed to followedChannels below,
  75.             // which contains channels followed via any means).
  76.             // ex: Disqus Picks is followed by too many people, if the forum were followed
  77.             // it would result in activities being copied to too many users' activity feeds.
  78.             this.channelsFollowing = new Feed({
  79.                 fetchOptions: fetchOptions,
  80.             }, {
  81.                 collectionClass: FollowingChannelCollection,
  82.             });
  83.             this.listenToOnce(this.channelsFollowing, 'items:sync', function () {
  84.                 this.user.set({
  85.                     numChannelsFollowing: this.channelsFollowing.items.length,
  86.                 });
  87.             });
  88.  
  89.             this.syncFollowingCommunities();
  90.  
  91.             this.following = new Feed({
  92.                 fetchOptions: fetchOptions,
  93.             }, {
  94.                 collectionClass: FollowingUserCollection,
  95.             });
  96.  
  97.             this.followers = new Feed({
  98.                 fetchOptions: fetchOptions,
  99.             }, {
  100.                 collectionClass: PaginatedUserCollection,
  101.                 collectionUrl: api.getURL('users/listFollowers'),
  102.             });
  103.  
  104.             this.mostActiveForums = new Feed({
  105.                 fetchOptions: {
  106.                     user: userFetchString,
  107.                     limit: 5,
  108.                 },
  109.             }, {
  110.                 collectionClass: MostActiveForumCollection,
  111.             });
  112.  
  113.             // A feed of channels the user manages: either as a mod or creator
  114.             this.managedChannels = new Feed(undefined, {
  115.                 collectionClass: UserManagedChannelCollection,
  116.                 collectionOptions: {
  117.                     user: this.user,
  118.                 },
  119.             });
  120.  
  121.             // A feed of channels the user follows, either directly or via a primary forum.
  122.             // Excludes managed channels, as those are fetched in another feed.
  123.             this.followedChannels = new Feed({
  124.                 fetchOptions: {
  125.                     user: userFetchString,
  126.  
  127.                     // Endpoint expects 1 for true, 0 for false
  128.                     includeFollowedPrimaryForums: 1,
  129.                     excludeModerated: 1,
  130.                     excludeOwned: 1,
  131.                 },
  132.             }, {
  133.                 collectionClass: FollowingChannelCollection,
  134.                 collectionOptions: {
  135.                     url: api.getURL('users/listFollowingChannels'),
  136.                 },
  137.             });
  138.  
  139.  
  140.             // For the endpoints that expect a target argument of the forum
  141.             // <object_type>:<object_id>
  142.             // ex: {target: 'user:username:joesmith'}
  143.             var target = 'user:' + userFetchString;
  144.  
  145.             this.posts = new Feed(undefined, {
  146.                 collectionClass: FeedItemCollection,
  147.                 collectionOptions: {
  148.                     type: 'profile',
  149.                     index: 'comments',
  150.                     target: target,
  151.                 },
  152.             });
  153.  
  154.             this.favorites = new Feed(undefined, {
  155.                 collectionClass: FeedItemCollection,
  156.                 collectionOptions: {
  157.                     type: 'profile',
  158.                     index: 'favorites',
  159.                     target: target,
  160.                 },
  161.             });
  162.  
  163.             this.threads = new Feed(undefined, {
  164.                 collectionClass: FeedItemCollection,
  165.                 collectionOptions: {
  166.                     type: 'profile',
  167.                     index: 'threads',
  168.                     target: target,
  169.                 },
  170.             });
  171.  
  172.             this.profileFeed = new Feed(undefined, {
  173.                 collectionClass: FeedItemCollection,
  174.                 collectionOptions: {
  175.                     type: 'profile',
  176.                     target: target,
  177.                 },
  178.             });
  179.  
  180.             this.moderationDetails = new UserModerationDetails({
  181.                 username: this.user.get('username'),
  182.             });
  183.  
  184.             this.listenTo(this.user, 'change:isOnGlobalBlacklist', this.handleChangeGlobalBlacklist);
  185.             this.listenTo(this.user, 'blacklist:add', this.removeUserDiscussions);
  186.             this.listenTo(this.user, 'change:username', this.updateUsernameInChildren);
  187.         },
  188.  
  189.         // On the frontend we want to treat followed channels and followed forums the
  190.         // same. Copy all the followed channels' primary forums into the followed
  191.         // forums list so they will be shown where we show followed communities.
  192.         syncFollowingCommunities: function () {
  193.             var forums = this.forumsFollowing.items;
  194.             var channels = this.channelsFollowing.items;
  195.  
  196.             this.listenTo(channels, {
  197.                 reset: function () {
  198.                     forums.add(_.pluck(channels.models, 'primaryForum'), { at: 0 });
  199.                 },
  200.                 add: function (channel) {
  201.                     forums.add(channel.primaryForum, { at: 0 });
  202.                 },
  203.                 remove: function (channel) {
  204.                     forums.remove(channel.primaryForum);
  205.                 },
  206.             });
  207.  
  208.             // When forumsFollowing is fetched it'll reset and overwrite all the forums
  209.             // manually added from followingChannels. Re-add them.
  210.             this.listenTo(forums, 'reset', function () {
  211.                 forums.add(_.pluck(channels.models, 'primaryForum'), { at: 0 });
  212.             });
  213.         },
  214.  
  215.         handleChangeGlobalBlacklist: function () {
  216.             if (!this.user.get('isOnGlobalBlacklist'))
  217.                 return;
  218.  
  219.             this.removeUserDiscussions();
  220.         },
  221.  
  222.         // Pages through all the user's discussions and deletes them. If a `forum` is
  223.         // passed, it'll only delete discussions from that forum.
  224.         removeUserDiscussions: function (forum) {
  225.             // If we've already fetched this user's discussions, go ahead and start
  226.             // loading the next page with `fetchItems()`. If we haven't fetched threads
  227.             // yet, call `ensureFetched()` because this handles the logic of not
  228.             // duplicating a fetch that's in progress.
  229.             var fetchPromise = this.threads.get('fetched') ? this.threads.fetchItems() : this.threads.ensureFetched();
  230.             fetchPromise.then(_.bind(function () {
  231.                 this.threads.items.each(function (threadActivity) {
  232.                     var thread = threadActivity.thread;
  233.                     if (forum && thread.forum.id !== forum)
  234.                         return;
  235.  
  236.                     thread.removeThread();
  237.                 });
  238.  
  239.                 // Repeat as long as there's more pages
  240.                 if (this.threads.get('hasNext'))
  241.                     this.removeUserDiscussions(forum);
  242.  
  243.             }, this));
  244.         },
  245.  
  246.         isPrivate: function () {
  247.             return !this.user.isSessionUser() && this.user.get('isPrivate');
  248.         },
  249.  
  250.         isBlocked: function () {
  251.             return !this.user.isSessionUser() && this.user.get('isBlocked');
  252.         },
  253.  
  254.         ensureFetched: function () {
  255.             // We require Session inline because of a circular dependency
  256.             // between the UserProfile and Session models
  257.             var Session = require('home/models/Session');
  258.             var session = Session.get();
  259.  
  260.             session.loadPromise().always(_.bind(function () {
  261.                 var isGlobalAdmin = session.user.isGlobalAdmin();
  262.                 // Wait until we can tell if the user is private
  263.                 // before fetching anything else
  264.                 backboneUtils.getPromiseFor(this.user, 'isPrivate').then(_.bind(function () {
  265.                     if (this.isPrivate() && !isGlobalAdmin)
  266.                         return;
  267.  
  268.                     this.favorites.ensureFetched();
  269.                     this.posts.ensureFetched();
  270.                     this.threads.ensureFetched();
  271.                     this.mostActiveForums.ensureFetched();
  272.  
  273.                     // Don't fetch followedChannels or managedChannels. Those are only
  274.                     // shown for the session user and are fetched directly when needed.
  275.  
  276.                     // numChannelsFollowing is not returned by the user details API endpoint
  277.                     // like both numFollowing (users) and numForumsFollowing are,
  278.                     // so we need to fetch channels to get the count
  279.                     this.channelsFollowing.ensureFetched();
  280.  
  281.                     // Only load moderation details for Disqus admins
  282.                     var self = this;
  283.                     if (isGlobalAdmin) {
  284.                         self.moderationDetails.ensureFetched();
  285.                         $.when(self.moderationDetails.fetchPromise).then(function () {
  286.                             self.trigger('moderationDetailsReady');
  287.                         });
  288.                     }
  289.                 }, this));
  290.  
  291.             }, this));
  292.  
  293.             this.fetchUser();
  294.         },
  295.  
  296.         ensureFetchedAllChannels: function () {
  297.             this.managedChannels.ensureFetched();
  298.             this.followedChannels.ensureFetched();
  299.         },
  300.  
  301.         toJSON: function () {
  302.             return _.defaults({
  303.                 user: this.user.toJSON(),
  304.                 following: this.following.toJSON(),
  305.                 followers: this.followers.toJSON(),
  306.                 mostActiveForums: this.mostActiveForums.toJSON(),
  307.                 posts: this.posts.toJSON(),
  308.                 threads: this.threads.toJSON(),
  309.                 profileFeed: this.profileFeed.toJSON(),
  310.                 moderationDetails: this.moderationDetails.toJSON(),
  311.             }, Backbone.Model.prototype.toJSON.call(this));
  312.         },
  313.  
  314.         /**
  315.          * Makes the necessary fetch calls in order to render the profile
  316.          * view for this user.
  317.          */
  318.         fetchUser: function () {
  319.             // If this user has an id, it should also have a username. Users
  320.             // get ids along with all the rest of the user details, whereas
  321.             // it's possible to have just a username with no other details.
  322.             if (!this.user.get('username'))
  323.                 throw new Error('UserProfile requires a username or id in order to be fetched');
  324.  
  325.             if (this.user.shouldFetch())
  326.                 this.user.fetch({ data: { user: 'username:' + this.user.get('username') } });
  327.         },
  328.  
  329.         fetchFollowing: function () {
  330.             this.following.fetchItems({ reset: true });
  331.         },
  332.  
  333.         fetchForumsFollowing: function () {
  334.             this.forumsFollowing.fetchItems({ reset: true });
  335.         },
  336.  
  337.         fetchChannelsFollowing: function () {
  338.             this.channelsFollowing.fetchItems({ reset: true });
  339.         },
  340.  
  341.         /**
  342.          * Updates the list of this user's followers when the
  343.          * session user follows/unfollows this user.
  344.          */
  345.         updateFollowers: function () {
  346.             var Session = require('home/models/Session');
  347.             var session = Session.get();
  348.  
  349.             // Don't add an anonymous user to the followers list.
  350.             //
  351.             // (If an anon user tried to follow someone, they'll be prompted
  352.             // to login. That happens elsewhere and may happen after this
  353.             // handler)
  354.             if (session.isAnonymous())
  355.                 return;
  356.  
  357.             var items = this.followers.get('items');
  358.             if (this.user.get('isFollowing'))
  359.                 items.add(session.user);
  360.             else
  361.                 items.remove(session.user);
  362.         },
  363.  
  364.         /**
  365.          * Updates an object's username.
  366.          * Meant to be used as an event listener
  367.          *
  368.          * @param  {Object} _model - the Backbone model that was updated
  369.          * @param  {string} username - the new username
  370.          * @returns {void}
  371.          */
  372.         updateUsername: function (_model, username) {
  373.             this.set('username', username);
  374.         },
  375.  
  376.         /**
  377.          * Updates the username for children.
  378.          * Meant to be used as an event listener, listening to changes to this.user.username.
  379.          *
  380.          * Doesn't need to update `this.managedChannels` because it has a reference to `this.user`.
  381.          *
  382.          * @param  {Object} _model - the Backbone model that was updated
  383.          * @param  {string} username - the new username
  384.          * @returns {void}
  385.          */
  386.         updateUsernameInChildren: function (_model, username) {
  387.             // Some places use `username:<username>` and others use `user:username:<username>`.
  388.             // The ones that use `username:<username>` are initialized with `fetchOptions`.
  389.             // The ones that use `user:username:<username>` are initialized with `collectionOptions`.
  390.             var targetUsername = 'username:' + username;
  391.             var usernameObj = { user: targetUsername };
  392.  
  393.             var objsUsingFetchOptions = [this.forumsFollowing, this.channelsFollowing, this.following,
  394.                 this.followers, this.mostActiveForums, this.followedChannels];
  395.             _.each(objsUsingFetchOptions, function (feed) {
  396.                 feed.set('fetchOptions', _.extend(feed.get('fetchOptions'), usernameObj));
  397.             });
  398.  
  399.             targetUsername = 'user:' + targetUsername;
  400.             var uniqueTogether = { target: targetUsername };
  401.  
  402.             var objsUsingUniqueTogether = [this.posts, this.favorites, this.threads, this.profileFeed];
  403.             _.each(objsUsingUniqueTogether, function (feed) {
  404.                 feed.items.updateUniqueTogether(uniqueTogether);
  405.             });
  406.  
  407.             this.moderationDetails.set('username', username); // Just has a reference to username
  408.         },
  409.     });
  410.  
  411.     UniqueModel.addType('UserProfile', UserProfile);
  412.  
  413.     return UserProfile;
  414. });
  415.  
  416. // https://c.disquscdn.com/next/82c6de3/home/js/models/UserProfile.js

Replies to UserProfile.js rss

Title Name Language When
Post.js disqus.com javascript 7 Months ago.
Post.js disqus.com javascript 7 Months ago.

Reply to "UserProfile.js"

Here you can reply to the paste above