<commit_before>'use strict';

var path = require('path');
var fs = require('fs-extra');
var _ = require('underscore');
var config = require('../../config/app-config');
var UPLOAD_DIR = config.UPLOAD_DIR;
var EVENT_IMG_DIR = config.EVENT_IMG_DIR;
var async = require('async');
var Event = require('../../models/Event');
var Image = require('../../models/Image');
var tmp = require('tmp');
var notificationService = require('../util/notificationService');

module.exports = function(req, res, next) {
    if (isCreate(req)) {
      console.log('Create event request', req.body);
    } else {
      console.log('Update event request', req.body);
    }

    var event;
    var reqImages = req.body.images || [];

    if (!isCreate(req)) {
      Event.findById(req.body._id, function(err, eventFound) {
        if (err) res.json(500, err); // TODO find out standard way to pass erorrs when UI will have standard error handler
        if (!eventFound || !eventFound.author.equals(req.user._id)) return res.json(404, {error: 'Event is not found'});
        event = eventFound;

        // merge images overriding from request
        var arr = _.partition((reqImages).concat(event.images || []), function(image) {
          return !_.isUndefined(image._id);
        });
        var imagesWithId = _.uniq(arr[0], function(image) {
          return image._id.toString();
        });
        var newImages = arr[1];
        var allImages = imagesWithId.concat(newImages);
        verifyLogoCount(allImages, doSave(newImages, imagesWithId));
      });
    } else {
      verifyLogoCount(reqImages, doSave(reqImages, []));
    }

    function verifyLogoCount(images, cb) {
      async.reduce(images, 0, countLogoImages, function(err, logoCount) {
        if (err) return res.json(500, err);
        console.log('verifyLogoCount', images.length, logoCount);
        if (images.length > 0 && logoCount != 1) {
          var errorMsg = 'Invalid logo count ' + logoCount;
          console.log(errorMsg);
          return res.json(400, {error: errorMsg});
        }
        cb();
      });
    }
    function doSave(newImages, imagesWithId) {
      return function() {
        async.map(newImages, copyImage, buildAndSaveEvent(event, imagesWithId, req, res, next));
      };
    }
};

function isCreate(req) {
  return _.isUndefined(req.body._id);
}

function countLogoImages(acc, image, next) {
  var add = image.isLogo ? 1 : 0;
  next(null, acc + add);
}

function buildAndSaveEvent(event, imagesWithId, req, res, next) {
    return function(err, images) {
        if (err) return res.json(500, err);

        delete req.body.images;

        if (event) {
          updateEvent();
        } else {
          createEvent();
        }

        function createEvent() {
          var eventObj = _.extend(req.body, {
            images: _.map(images, function(image){
              return new Image(image);
            }),
            author: req.user._id
          });
          console.log('Creating event ', eventObj);
          event = new Event(eventObj);
          event.save(afterSave(event));
        }

        function updateEvent() {
          _.extend(event, req.body, {images: images.concat(imagesWithId)});

          console.log('Updating event by id', event._id, event);
          var respEvent = _.extend({}, event, {_id: event._id});
          event.save(afterSave(respEvent));
        }

        function afterSave(event) {
          return function(err) {
            if (err) return res.json(400, {error: err});

            if(isCreate(req)) notificationService.notifyAuthorOnCreate(event);
              else notificationService.notifyParticipantOnEdit(event);

            var respJson = {event: event};
            console.log('Sending response ', respJson);
            req.flash('success', { msg: isCreate(req) ? 'Ваше событие создано!': 'Ваше событие обновлено!' });
            res.send(respJson);
          }
        }
    };
}

function copyImage(image, next) {
    console.log('Verify image ', image);

  // Siman: Image uploading works for me if comment next line. Does it work on Linux as well?
//    var imagePath = path.join('/', image.name); // removes any '..'
    var imagePath = path.join(UPLOAD_DIR, image.name);

    fs.exists(imagePath, function(exists) {
        console.log('Image exists ', exists);
        console.log('uploadDir ', UPLOAD_DIR);
        if (exists && imagePath.indexOf(UPLOAD_DIR) == 0) {
            moveFile(imagePath, EVENT_IMG_DIR, function(err, newPath) {
                next(err, _.extend(image, {name: path.basename(newPath)}));
            });
        } else {
            next(null, image);
        }
    });
}

/**
 * Move file to specified directory generating unique name preserving file extension.
 * @param srcPath - source file path
 * @param destDir - destination dir
 * @param fileExtension - extension of the file
 * @param next
 */
function moveFile(srcPath, destDir, next) {
    tmp.tmpName({ dir: destDir, prefix: 'event-', postfix: path.extname(srcPath), tries: 100},
      function(err, destPath) {
        console.log('Created unique name ', destPath);
        console.log('Moving ', srcPath, ' to ', destPath);
        fs.copy(srcPath, destPath, function(err) {
            if (err) return next(err);

            fs.unlink(srcPath, function(err) {
                if (err) {
                    console.error('Cannot unlink file ', srcPath, err);
                }
                next(null, destPath);
            });
        });
    });
}<commit_msg>Typo fix<commit_after>'use strict';

var path = require('path');
var fs = require('fs-extra');
var _ = require('underscore');
var config = require('../../config/app-config');
var UPLOAD_DIR = config.UPLOAD_DIR;
var EVENT_IMG_DIR = config.EVENT_IMG_DIR;
var async = require('async');
var Event = require('../../models/Event');
var Image = require('../../models/Image');
var tmp = require('tmp');
var notificationService = require('../util/notificationService');

module.exports = function(req, res, next) {
    if (isCreate(req)) {
      console.log('Create event request', req.body);
    } else {
      console.log('Update event request', req.body);
    }

    var event;
    var reqImages = req.body.images || [];

    if (!isCreate(req)) {
      Event.findById(req.body._id, function(err, eventFound) {
        if (err) res.json(500, err); // TODO find out standard way to pass errors when UI will have standard error handler
        if (!eventFound || !eventFound.author.equals(req.user._id)) return res.json(404, {error: 'Event is not found'});
        event = eventFound;

        // merge images overriding from request
        var arr = _.partition((reqImages).concat(event.images || []), function(image) {
          return !_.isUndefined(image._id);
        });
        var imagesWithId = _.uniq(arr[0], function(image) {
          return image._id.toString();
        });
        var newImages = arr[1];
        var allImages = imagesWithId.concat(newImages);
        verifyLogoCount(allImages, doSave(newImages, imagesWithId));
      });
    } else {
      verifyLogoCount(reqImages, doSave(reqImages, []));
    }

    function verifyLogoCount(images, cb) {
      async.reduce(images, 0, countLogoImages, function(err, logoCount) {
        if (err) return res.json(500, err);
        console.log('verifyLogoCount', images.length, logoCount);
        if (images.length > 0 && logoCount != 1) {
          var errorMsg = 'Invalid logo count ' + logoCount;
          console.log(errorMsg);
          return res.json(400, {error: errorMsg});
        }
        cb();
      });
    }
    function doSave(newImages, imagesWithId) {
      return function() {
        async.map(newImages, copyImage, buildAndSaveEvent(event, imagesWithId, req, res, next));
      };
    }
};

function isCreate(req) {
  return _.isUndefined(req.body._id);
}

function countLogoImages(acc, image, next) {
  var add = image.isLogo ? 1 : 0;
  next(null, acc + add);
}

function buildAndSaveEvent(event, imagesWithId, req, res, next) {
    return function(err, images) {
        if (err) return res.json(500, err);

        delete req.body.images;

        if (event) {
          updateEvent();
        } else {
          createEvent();
        }

        function createEvent() {
          var eventObj = _.extend(req.body, {
            images: _.map(images, function(image){
              return new Image(image);
            }),
            author: req.user._id
          });
          console.log('Creating event ', eventObj);
          event = new Event(eventObj);
          event.save(afterSave(event));
        }

        function updateEvent() {
          _.extend(event, req.body, {images: images.concat(imagesWithId)});

          console.log('Updating event by id', event._id, event);
          var respEvent = _.extend({}, event, {_id: event._id});
          event.save(afterSave(respEvent));
        }

        function afterSave(event) {
          return function(err) {
            if (err) return res.json(400, {error: err});

            if(isCreate(req)) notificationService.notifyAuthorOnCreate(event);
              else notificationService.notifyParticipantOnEdit(event);

            var respJson = {event: event};
            console.log('Sending response ', respJson);
            req.flash('success', { msg: isCreate(req) ? 'Ваше событие создано!': 'Ваше событие обновлено!' });
            res.send(respJson);
          }
        }
    };
}

function copyImage(image, next) {
    console.log('Verify image ', image);

  // Siman: Image uploading works for me if comment next line. Does it work on Linux as well?
//    var imagePath = path.join('/', image.name); // removes any '..'
    var imagePath = path.join(UPLOAD_DIR, image.name);

    fs.exists(imagePath, function(exists) {
        console.log('Image exists ', exists);
        console.log('uploadDir ', UPLOAD_DIR);
        if (exists && imagePath.indexOf(UPLOAD_DIR) == 0) {
            moveFile(imagePath, EVENT_IMG_DIR, function(err, newPath) {
                next(err, _.extend(image, {name: path.basename(newPath)}));
            });
        } else {
            next(null, image);
        }
    });
}

/**
 * Move file to specified directory generating unique name preserving file extension.
 * @param srcPath - source file path
 * @param destDir - destination dir
 * @param fileExtension - extension of the file
 * @param next
 */
function moveFile(srcPath, destDir, next) {
    tmp.tmpName({ dir: destDir, prefix: 'event-', postfix: path.extname(srcPath), tries: 100},
      function(err, destPath) {
        console.log('Created unique name ', destPath);
        console.log('Moving ', srcPath, ' to ', destPath);
        fs.copy(srcPath, destPath, function(err) {
            if (err) return next(err);

            fs.unlink(srcPath, function(err) {
                if (err) {
                    console.error('Cannot unlink file ', srcPath, err);
                }
                next(null, destPath);
            });
        });
    });
}<|endoftext|>


<commit_before>;(function (global, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['knockout', 'jquery', 'knockoutpunches', 'History', 'osfutils'], factory);
    } else {
        global.Search  = factory(ko, jQuery, History);
    }
}(this, function(ko, $, History) {
    // Enable knockout punches
    ko.punches.enableAll();

    //https://stackoverflow.com/questions/7731778/jquery-get-query-string-parameters
    function qs(key) {
        key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, '\\$&'); // escape RegEx meta chars
        var match = location.search.match(new RegExp('[?&]'+key+'=([^&]+)(&|$)'));
        return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
    }

    var Category = function(name, count, display){
        var self = this;

        self.name = ko.observable(name);
        self.count = ko.observable(count);
        self.display = ko.observable(display);

        self.url = ko.computed(function() {
            if (self.name() === 'total') {
                return '';
            }
            return self.name() + '/';
        });
    };

    var Tag = function(tagInfo){
        var self = this;
        self.name = ko.observable(tagInfo.key);
        self.count = ko.observable(tagInfo.doc_count);
    };

    var ViewModel = function(params) {
        var self = this;
        self.params = params || {};
        console.log(params);
        console.log(self.params);
        self.queryUrl = self.params.url;
        self.appURL = self.params.appURL;

        self.tag = ko.observable('');
        self.stateJustPushed = false;
        self.query = ko.observable('');
        self.category = ko.observable({});
        self.tags = ko.observableArray([]);
        self.tagMaxCount = ko.observable(1);
        self.currentPage = ko.observable(1);
        self.totalResults = ko.observable(0);
        self.results = ko.observableArray([]);
        self.searching = ko.observable(false);
        self.resultsPerPage = ko.observable(10);
        self.categories = ko.observableArray([]);
        self.searchStarted = ko.observable(false);

        self.totalCount = ko.computed(function() {
            if (self.categories().length === 0 || self.categories()[0] === undefined) {
                return 0;
            }

            return self.categories()[0].count();
        });

        self.totalPages = ko.computed(function() {
            var resultsCount = Math.max(self.resultsPerPage(),1); // No Divide by Zero
            countOfPages = Math.ceil(self.totalResults() / resultsCount);
            return countOfPages;
        });

        self.nextPageExists = ko.computed(function() {
            return ((self.totalPages() > 1) && (self.currentPage() < self.totalPages()));
        });

        self.prevPageExists = ko.computed(function() {
            return self.totalPages() > 1 && self.currentPage() > 1;
        });

        self.currentIndex = ko.computed(function() {
            return Math.max(self.resultsPerPage() * (self.currentPage()-1),0);
        });

        self.navLocation = ko.computed(function() {
            return 'Page ' + self.currentPage() + ' of ' + self.totalPages();
        });

        self.queryObject = ko.computed(function(){
            return {
                'query_string': {
                    'default_field': '_all',
                    'query': self.query(),
                    'analyze_wildcard': true,
                    'lenient': true
                }
            };
        });

        self.fullQuery = ko.computed(function() {
            return {
                'filtered': {
                    'query': self.queryObject()
                }
            };
        });

        self.sortCategories = function(a, b) {
            if(a.name() === 'Total') {
                return -1;
            } else if (b.name() === 'Total') {
                return 1;
            }
            return a.count() >  b.count() ? -1 : 1;
        };

        self.claim = function(mid) {
            claimURL = self.appURL + 'metadata/' + mid + '/promote/';
            $.osf.postJSON(claimURL, {category: 'project'}).success(function(data) {
                window.location = data.url;
            });
        };

        self.help = function() {
            bootbox.dialog({
                title: 'Search help',
                message: '
Queries
'+
                    '
Search uses the Lucene search syntax. ' +
                    'This gives you many options, but can be very simple as well. ' +
                    'Examples of valid searches include:' +
                    '

repro*
' +
                    '
brian AND title:many
' +
                    '
tags:(psychology)

' +
                    '
'
            });
        };

        self.filter = function(alias) {
            self.searchStarted(false);
            self.currentPage(1);
            self.category(alias);
            self.search();
        };

        self.addTag = function(name) {
            // To handle passing from template vs. in main html
            var tag = name;

            if(typeof name.name !== 'undefined') {
                tag = name.name();
            }

            self.currentPage(1);
            self.query(self.query() + ' AND tags:("' + tag + '")');
            self.search();
        };

        self.submit = function() {
            self.searchStarted(false);
            self.totalResults(0);
            self.currentPage(1);
            self.search();
        };

        self.search = function(noPush, validate) {
            self.tagMaxCount(1);
            var jsonData = {'query': self.fullQuery(), 'from': self.currentIndex(), 'size': self.resultsPerPage()};
            var url = self.queryUrl + self.category().url();

            $.osf.postJSON(url, jsonData).success(function(data) {

                //Clear out our variables
                self.tags([]);
                self.results.removeAll();
                self.categories.removeAll();

                data.results.forEach(function(result){
                    if(typeof result.url !== 'undefined'){
                        result.wikiUrl = result.url+'wiki/';
                        result.filesUrl = result.url+'files/';
                    }
                    self.results.push(result);
                });

                //Load our categories
                var categories = data.counts;
                $.each(categories, function(key, value){
                    if (value === null) {
                        value = 0;
                    }
                    self.categories.push(new Category(key, value, data.typeAliases[key]));
                });
                self.categories(self.categories().sort(self.sortCategories));

                // If our category is named attempt to load its total else set it to the total total
                if (self.category().name !== undefined) {
                    self.totalResults(data.counts[self.category().name()] || 0);
                } else {
                    self.totalResults(self.self.categories()[0].count());
                }

                // Load up our tags
                $.each(data.tags, function(key, value){
                    self.tags.push(new Tag(value));
                    self.tagMaxCount(Math.max(self.tagMaxCount(), value.doc_count));
                });

                self.searchStarted(true);

                if (validate) {
                    self.validateSearch();
                }

                if (!noPush) {
                    self.pushState();
                }

            }).fail(function(response){
                self.totalResults(0);
                self.currentPage(0);
                self.results([]);
                self.tags([]);
                self.categories([]);
                self.searchStarted(false);
                $.osf.handleJSONError(response);
            });

        };

        self.paginate = function(val) {
            window.scrollTo(0, 0);
            self.currentPage(self.currentPage()+val);
            self.search();
        };

        self.pagePrev = self.paginate.bind(self, -1);
        self.pageNext = self.paginate.bind(self, 1);

        //History JS callback
        self.pageChange = function() {
            if (self.stateJustPushed) {
                self.stateJustPushed = false;
                return;
            }

            self.loadState();

            self.search(true);
        };

        //Ensure that the first url displays properly
        self.validateSearch = function() {
            if (self.category().name !== undefined) {
                possibleCategories = $.map(self.categories().filter(function(category) {
                    return category.count() > 0;
                }), function(category) {
                    return category.name();
                });

                if (possibleCategories.indexOf(self.category().name()) === -1) {
                    self.filter(self.categories()[0]);
                    return self.search(true);
                }
            }
            if (self.currentPage() > self.totalPages()) {
                self.currentPage(self.totalPages());
                return self.search(true);
            }
        };

        //Load state from History JS
        self.loadState = function() {
            var state = History.getState().data;
            self.currentPage(state.page || 1);
            self.setCategory(state.filter);
            self.query(state.query || '');
        };

        //Push a new state to History
        self.pushState = function() {
            var state = {
                filter: '',
                query: self.query(),
                page: self.currentPage(),
                scrollTop: $(window).scrollTop()
            };

            var url = '?q=' + self.query();

            if (self.category().name !== undefined && self.category().url() !== '') {
                state.filter = self.category().name();
                url += ('&filter=' + self.category().name());
            }

            url += ('&page=' + self.currentPage());

            //Indicate that we've just pushed a state so the
            //Call back does not process this push as a state change
            self.stateJustPushed = true;
            History.pushState(state, 'OSF | Search', url);
        };

        self.setCategory = function(cat) {
            if (cat !== undefined && cat !== null && cat !== '') {
                self.category(new Category(cat, 0, cat.charAt(0).toUpperCase() + cat.slice(1) + 's'));
            } else {
                self.category(new Category('total', 0, 'Total'));
            }
        };

    };

    function Search(selector, url, appURL) {
        // Initialization code
        var self = this;

        self.viewModel = new ViewModel({'url': url, 'appURL': appURL});
        History.Adapter.bind(window, 'statechange', self.viewModel.pageChange);

        var data = {
            query: qs('q'),
            page: Number(qs('page')),
            scrollTop: 0,
            filter: qs('filter')
        };
        //Ensure our state keeps its URL paramaters
        History.replaceState(data, 'OSF | Search', location.search);
        //Set out observables from the newly replaced state
        self.viewModel.loadState();
        //Preform search from url params
        self.viewModel.search(true, true);

        $.osf.applyBindings(self.viewModel, selector);
    }

    return Search;

}));
<commit_msg>Don't link to anchor on Lucene Search Help Page<commit_after>;(function (global, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['knockout', 'jquery', 'knockoutpunches', 'History', 'osfutils'], factory);
    } else {
        global.Search  = factory(ko, jQuery, History);
    }
}(this, function(ko, $, History) {
    // Enable knockout punches
    ko.punches.enableAll();

    //https://stackoverflow.com/questions/7731778/jquery-get-query-string-parameters
    function qs(key) {
        key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, '\\$&'); // escape RegEx meta chars
        var match = location.search.match(new RegExp('[?&]'+key+'=([^&]+)(&|$)'));
        return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
    }

    var Category = function(name, count, display){
        var self = this;

        self.name = ko.observable(name);
        self.count = ko.observable(count);
        self.display = ko.observable(display);

        self.url = ko.computed(function() {
            if (self.name() === 'total') {
                return '';
            }
            return self.name() + '/';
        });
    };

    var Tag = function(tagInfo){
        var self = this;
        self.name = ko.observable(tagInfo.key);
        self.count = ko.observable(tagInfo.doc_count);
    };

    var ViewModel = function(params) {
        var self = this;
        self.params = params || {};
        console.log(params);
        console.log(self.params);
        self.queryUrl = self.params.url;
        self.appURL = self.params.appURL;

        self.tag = ko.observable('');
        self.stateJustPushed = false;
        self.query = ko.observable('');
        self.category = ko.observable({});
        self.tags = ko.observableArray([]);
        self.tagMaxCount = ko.observable(1);
        self.currentPage = ko.observable(1);
        self.totalResults = ko.observable(0);
        self.results = ko.observableArray([]);
        self.searching = ko.observable(false);
        self.resultsPerPage = ko.observable(10);
        self.categories = ko.observableArray([]);
        self.searchStarted = ko.observable(false);

        self.totalCount = ko.computed(function() {
            if (self.categories().length === 0 || self.categories()[0] === undefined) {
                return 0;
            }

            return self.categories()[0].count();
        });

        self.totalPages = ko.computed(function() {
            var resultsCount = Math.max(self.resultsPerPage(),1); // No Divide by Zero
            countOfPages = Math.ceil(self.totalResults() / resultsCount);
            return countOfPages;
        });

        self.nextPageExists = ko.computed(function() {
            return ((self.totalPages() > 1) && (self.currentPage() < self.totalPages()));
        });

        self.prevPageExists = ko.computed(function() {
            return self.totalPages() > 1 && self.currentPage() > 1;
        });

        self.currentIndex = ko.computed(function() {
            return Math.max(self.resultsPerPage() * (self.currentPage()-1),0);
        });

        self.navLocation = ko.computed(function() {
            return 'Page ' + self.currentPage() + ' of ' + self.totalPages();
        });

        self.queryObject = ko.computed(function(){
            return {
                'query_string': {
                    'default_field': '_all',
                    'query': self.query(),
                    'analyze_wildcard': true,
                    'lenient': true
                }
            };
        });

        self.fullQuery = ko.computed(function() {
            return {
                'filtered': {
                    'query': self.queryObject()
                }
            };
        });

        self.sortCategories = function(a, b) {
            if(a.name() === 'Total') {
                return -1;
            } else if (b.name() === 'Total') {
                return 1;
            }
            return a.count() >  b.count() ? -1 : 1;
        };

        self.claim = function(mid) {
            claimURL = self.appURL + 'metadata/' + mid + '/promote/';
            $.osf.postJSON(claimURL, {category: 'project'}).success(function(data) {
                window.location = data.url;
            });
        };

        self.help = function() {
            bootbox.dialog({
                title: 'Search help',
                message: '
Queries
'+
                    '
Search uses the Lucene search syntax. ' +
                    'This gives you many options, but can be very simple as well. ' +
                    'Examples of valid searches include:' +
                    '

repro*
' +
                    '
brian AND title:many
' +
                    '
tags:(psychology)

' +
                    '
'
            });
        };

        self.filter = function(alias) {
            self.searchStarted(false);
            self.currentPage(1);
            self.category(alias);
            self.search();
        };

        self.addTag = function(name) {
            // To handle passing from template vs. in main html
            var tag = name;

            if(typeof name.name !== 'undefined') {
                tag = name.name();
            }

            self.currentPage(1);
            self.query(self.query() + ' AND tags:("' + tag + '")');
            self.search();
        };

        self.submit = function() {
            self.searchStarted(false);
            self.totalResults(0);
            self.currentPage(1);
            self.search();
        };

        self.search = function(noPush, validate) {
            self.tagMaxCount(1);
            var jsonData = {'query': self.fullQuery(), 'from': self.currentIndex(), 'size': self.resultsPerPage()};
            var url = self.queryUrl + self.category().url();

            $.osf.postJSON(url, jsonData).success(function(data) {

                //Clear out our variables
                self.tags([]);
                self.results.removeAll();
                self.categories.removeAll();

                data.results.forEach(function(result){
                    if(typeof result.url !== 'undefined'){
                        result.wikiUrl = result.url+'wiki/';
                        result.filesUrl = result.url+'files/';
                    }
                    self.results.push(result);
                });

                //Load our categories
                var categories = data.counts;
                $.each(categories, function(key, value){
                    if (value === null) {
                        value = 0;
                    }
                    self.categories.push(new Category(key, value, data.typeAliases[key]));
                });
                self.categories(self.categories().sort(self.sortCategories));

                // If our category is named attempt to load its total else set it to the total total
                if (self.category().name !== undefined) {
                    self.totalResults(data.counts[self.category().name()] || 0);
                } else {
                    self.totalResults(self.self.categories()[0].count());
                }

                // Load up our tags
                $.each(data.tags, function(key, value){
                    self.tags.push(new Tag(value));
                    self.tagMaxCount(Math.max(self.tagMaxCount(), value.doc_count));
                });

                self.searchStarted(true);

                if (validate) {
                    self.validateSearch();
                }

                if (!noPush) {
                    self.pushState();
                }

            }).fail(function(response){
                self.totalResults(0);
                self.currentPage(0);
                self.results([]);
                self.tags([]);
                self.categories([]);
                self.searchStarted(false);
                $.osf.handleJSONError(response);
            });

        };

        self.paginate = function(val) {
            window.scrollTo(0, 0);
            self.currentPage(self.currentPage()+val);
            self.search();
        };

        self.pagePrev = self.paginate.bind(self, -1);
        self.pageNext = self.paginate.bind(self, 1);

        //History JS callback
        self.pageChange = function() {
            if (self.stateJustPushed) {
                self.stateJustPushed = false;
                return;
            }

            self.loadState();

            self.search(true);
        };

        //Ensure that the first url displays properly
        self.validateSearch = function() {
            if (self.category().name !== undefined) {
                possibleCategories = $.map(self.categories().filter(function(category) {
                    return category.count() > 0;
                }), function(category) {
                    return category.name();
                });

                if (possibleCategories.indexOf(self.category().name()) === -1) {
                    self.filter(self.categories()[0]);
                    return self.search(true);
                }
            }
            if (self.currentPage() > self.totalPages()) {
                self.currentPage(self.totalPages());
                return self.search(true);
            }
        };

        //Load state from History JS
        self.loadState = function() {
            var state = History.getState().data;
            self.currentPage(state.page || 1);
            self.setCategory(state.filter);
            self.query(state.query || '');
        };

        //Push a new state to History
        self.pushState = function() {
            var state = {
                filter: '',
                query: self.query(),
                page: self.currentPage(),
                scrollTop: $(window).scrollTop()
            };

            var url = '?q=' + self.query();

            if (self.category().name !== undefined && self.category().url() !== '') {
                state.filter = self.category().name();
                url += ('&filter=' + self.category().name());
            }

            url += ('&page=' + self.currentPage());

            //Indicate that we've just pushed a state so the
            //Call back does not process this push as a state change
            self.stateJustPushed = true;
            History.pushState(state, 'OSF | Search', url);
        };

        self.setCategory = function(cat) {
            if (cat !== undefined && cat !== null && cat !== '') {
                self.category(new Category(cat, 0, cat.charAt(0).toUpperCase() + cat.slice(1) + 's'));
            } else {
                self.category(new Category('total', 0, 'Total'));
            }
        };

    };

    function Search(selector, url, appURL) {
        // Initialization code
        var self = this;

        self.viewModel = new ViewModel({'url': url, 'appURL': appURL});
        History.Adapter.bind(window, 'statechange', self.viewModel.pageChange);

        var data = {
            query: qs('q'),
            page: Number(qs('page')),
            scrollTop: 0,
            filter: qs('filter')
        };
        //Ensure our state keeps its URL paramaters
        History.replaceState(data, 'OSF | Search', location.search);
        //Set out observables from the newly replaced state
        self.viewModel.loadState();
        //Preform search from url params
        self.viewModel.search(true, true);

        $.osf.applyBindings(self.viewModel, selector);
    }

    return Search;

}));
<|endoftext|>


<commit_before>import React, { Component } from "react";

import TimeUtil from "../util/TimeUtil";

export default class PlayerView extends Component
{
    constructor(props)
    {
        super(props);
    }

    static propTypes = {
        selectedTrack: React.PropTypes.object
    }

    static defaultProps = {
        selectedTrack: null
    }

    state = {
        onPlayTrack: null,
        playState: false,
        duration: "/00:00",
        currentTime: "00:00",
        imgSrc: "",
        artistName: "",
        trackName: "未知",
        readyState: "false",
        trackList: []
    }

    componentWillReceiveProps(nextProps)
    {
        this._initPlayer();
        // this.playStateBtn.classList.add("clickDisabled");
        this._initSelectedTrack(nextProps.selectedTrack);

        if (nextProps.trackList)
        {
            this.setState({ trackList: nextProps.trackList });
        }
        else
        {
            this.setState({ trackList: [] });
        }
    }

    componentDidMount()
    {
        this.setState({
            onPlayTrack: this.props.selectedTrack
        });

        this.audio = this.refs["audio"];
        this.playingBar = this.refs["playingBar"];
        this.volumeBar = this.refs["volumeBar"];
        this.playStateBtn = this.refs["playStateBtn"];
        this.processIcon = this.refs["processIcon"];
        this.volumeIcon = this.refs["volumeIcon"];
        this.audio.volume = 0.5;
        this.volumeIcon.style.left =  "42px";
        this.volumeBar.style.width = "50px";

        this.audio.onended = () => {
            this._initPlayer();
            this.audio.play();
            this.setState({ playState : true });
        };

        this.audio.onerror = () => {
            // alert("视频加载出错");
        };

        this.audio.oncanplay = () => {
            this.playStateBtn.classList.remove("icon-play");
            this.playStateBtn.classList.add("icon-pause");
            // this.playStateBtn.classList.remove("clickDisabled");
            this.audio.play();
            this.setState({ playState : true });
            this.forceUpdate();
        };

        this.audio.ontimeupdate = () => {
            const offset = Math.round( this.audio.currentTime * 500 / this.audio.duration );
            this.playingBar.style.width = offset + "px";
            this.processIcon.style.left = (offset - 8) + "px";
            this.setState({ currentTime: TimeUtil.formateTime(this.audio.currentTime * 1000) });
            this.forceUpdate();
        };

        this.volumeIcon.ondragstart = (e) => {
            const parentLeft = e.clientX - this.processIcon.offsetLeft;
            this.processIcon.ondrag = (e1) => {
                let left = e1.clientX - parentLeft;
                let width = 0;
                if (left < 0)
                {
                    left = 0;
                }
                else if (left > 492)
                {
                    left = 492;
                    width =500;
                }
                else
                {
                    width = left + 8;
                }
                this.processIcon.style.left = left + "px";
                this.playingBar.style.width = width + "px";
            };

            this.processIcon.ondragend = (e1) => {
                let left = e1.clientX - parentLeft;
                let width = 0;
                if (left < 0)
                {
                    left = 0;
                }
                else if (left > 492)
                {
                    left = 492;
                    width =500;
                }
                else
                {
                    width = left + 8;
                }
                this.processIcon.style.left = left + "px";
                this.playingBar.style.width = width + "px";

                const currentTime = (Math.round(this.audio.duration * width / 500));
                this.audio.currentTime = currentTime;
            };
        };

        this.volumeIcon.ondragstart = (e) => {
            const parentLeft = e.clientX - this.volumeIcon.offsetLeft;
            this.volumeIcon.ondrag = (e1) => {
                let left = e1.clientX - parentLeft;
                let width = 0;
                if (left < 0)
                {
                    left = 0;
                }
                else if (left > 92)
                {
                    left = 92;
                    width =100;
                }
                else
                {
                    width = left + 8;
                }
                this.volumeIcon.style.left = left + "px";
                this.volumeBar.style.width = width + "px";
            };

            this.volumeIcon.ondragend = (e1) => {
                let left = e1.clientX - parentLeft;
                let width = 0;
                if (left < 0)
                {
                    left = 0;
                }
                else if (left > 92)
                {
                    left = 92;
                    width =100;
                }
                else
                {
                    width = left + 8;
                }
                this.volumeIcon.style.left = left + "px";
                this.volumeBar.style.width = width + "px";

                const volume = width / 100;
                this.audio.volume = volume;

            };
        };
    }

    render()
    {
        return (

                    { this.state.trackName }
                    { this.state.artistName }

{ this.state.currentTime + this.state.duration }

            <audio ref="audio" className="music-player" src={ this.state.mp3Url } draggable="true" controls="controls">
            </audio>

);
    }

    _prevTrack()
    {
        const index = this.state.trackList.indexOf(this.state.onPlayTrack);
        if (index === 0)
        {
            alert("the last music not exists!");
        }
        else
        {
            const track = this.state.trackList[index-1 > 0 ? index - 1 : 0 ];
            this.setState({ onPlayTrack:  track });
            this._initSelectedTrack(track);
        }
    }

    _nextTrack()
    {
        const index = this.state.trackList.indexOf(this.state.onPlayTrack);
        if (index === this.state.trackList.length)
        {
            alert("Now it is the lastest music");
        }
        else
        {
            const track = this.state.trackList[index + 1 > 0 ? index + 1 : 0 ];
            this.setState({ onPlayTrack: track });
            this._initSelectedTrack(track);
        }
    }

    _togglePlay()
    {
        if (!this.state.readyState) return ; //效果后续添加
        if (this.state.playState === true)
        {
            this.playStateBtn.classList.remove("icon-pause");
            this.playStateBtn.classList.add("icon-play");
            this.audio.pause();
            this.setState({ playState : false });
        }
        else
        {
            this.playStateBtn.classList.remove("icon-play");
            this.playStateBtn.classList.add("icon-pause");
            this.audio.play();
            this.setState({ playState : true });
        }
    }

    _initPlayer()
    {
        this.setState({ playState: false });
        this.playStateBtn.classList.remove("icon-pause");
        this.playStateBtn.classList.add("icon-play");
        this.playingBar.style.width = "0px";
        this.processIcon.style.left = "0px";
    }

    _initSelectedTrack(track)
    {
        if (track)
        {
            let duration = 0;
            if (track.lMusic)
            {
                duration = track.lMusic.playTime;
            }
            else
            {
                duration = track.duration;
            }
            this.setState({
                onPlayTrack: track,
                playState: false,
                duration: "/" + TimeUtil.formateTime(duration),
                currentTime: "00:00",
                imgSrc: track.album.blurPicUrl,
                artistName: track.artists.map(artist => artist.name).join(","),
                trackName: track.name,
                mp3Url: track.mp3Url
            });
        }
        else
        {
            this.setState({
                onPlayTrack: null,
                playState: false,
                duration: "/00:00",
                currentTime: "00:00",
                imgSrc: "",
                artistName: "",
                trackName: "未知",
                mp3Url: ""
            });
        }
    }
}
<commit_msg>Fixed the location bug for dragable bar.<commit_after>import React, {Component} from "react";

import TimeUtil from "../util/TimeUtil";

export default class PlayerView extends Component
{
    constructor(props)
    {
        super(props);
        this._toggleSound = this._toggleSound.bind(this);
        this._handleProcess = this._handleProcess.bind(this);
        this._handleVolume = this._handleVolume.bind(this);
        this._processControl = this._processControl.bind(this);
        this._volumeControl = this._volumeControl.bind(this);
    }

    static propTypes = {
        selectedTrack: React.PropTypes.object
    }

    static defaultProps = {
        selectedTrack: null
    }

    state = {
        onPlayTrack: null,
        playState: false,
        duration: "/00:00",
        currentTime: "00:00",
        imgSrc: "",
        artistName: "",
        trackName: "未知",
        readyState: "false",
        trackList: [],
        muted: false    //是否静音

    }

    componentWillReceiveProps(nextProps) {
        this._initPlayer();
        // this.playStateBtn.classList.add("clickDisabled");
        this._initSelectedTrack(nextProps.selectedTrack);

        if (nextProps.trackList) {
            this.setState({trackList: nextProps.trackList});
        }
        else {
            this.setState({trackList: []});
        }
    }

    componentDidMount() {
        this.setState({
            onPlayTrack: this.props.selectedTrack
        });

        this.dragImage = document.createElementNS("http://www.w3.org/1999/xhtml","html:canvas");
        this.audio = this.refs["audio"];
        this.playingBar = this.refs["playingBar"];
        this.volumeBar = this.refs["volumeBar"];
        this.playStateBtn = this.refs["playStateBtn"];
        this.processIcon = this.refs["processIcon"];
        this.volumeIcon = this.refs["volumeIcon"];
        this.audio.volume = 0.5;
        this.volumeIcon.style.left =  "42px";
        this.volumeBar.style.width = "50px";

        this.audio.onended = () => {
            this._initPlayer();
            this.audio.play();
            this.setState({playState : true});
        };

        this.audio.onerror = () => {
            // alert("视频加载出错");
        };

        this.audio.oncanplay = () => {
            this.playStateBtn.classList.remove("icon-play");
            this.playStateBtn.classList.add("icon-pause");
            // this.playStateBtn.classList.remove("clickDisabled");
            this.audio.play();
            this.setState({playState : true});
            this.forceUpdate();
        };

        this.audio.ontimeupdate = () => {
            const offset = Math.round(this.audio.currentTime * 500 / this.audio.duration );
            this.playingBar.style.width = offset + "px";
            this.processIcon.style.left = (offset - 8) + "px";
            this.setState({currentTime: TimeUtil.formateTime(this.audio.currentTime * 1000)});
            this.forceUpdate();
        };

        this.processIcon.ondragstart = (e) => {
            const parentLeft = e.clientX - this.processIcon.offsetLeft;
            this.processIcon.ondrag = (e1) => {
                e1.dataTransfer.setDragImage(this.dragImage, 0, 0);
                if (e1.x === 0 && e1.y === 0) {
                    return;
                }
                const left = e1.clientX - parentLeft;
                this._processControl(left, true);
            };
        };

        this.volumeIcon.ondragstart = (e) => {
            const parentLeft = e.clientX - this.volumeIcon.offsetLeft;
            this.volumeIcon.ondrag = (e1) => {

                e1.dataTransfer.setDragImage(this.dragImage, 0, 0);
                if (e1.x === 0 && e1.y === 0) {
                    return;
                }
                const left = e1.clientX - parentLeft;
                this._volumeControl(left, true);
            };
        };
    }

    render()
    {
        return (

                    { this.state.trackName }
                    { this.state.artistName }

{ this.state.currentTime + this.state.duration }

                    <a className={`track-volume iconfont ${this.state.muted ? 'icon-soundminus' : 'icon-soundplus'}` } onClick={this._toggleSound.bind(this)}>

            <audio ref="audio" className="music-player" src={ this.state.mp3Url } draggable="true" controls="controls" muted={this.state.muted}>
            </audio>

);
    }

    _prevTrack()
    {
        const index = this.state.trackList.indexOf(this.state.onPlayTrack);
        if (index === 0)
        {
            alert("the last music not exists!");
        }
        else
        {
            const track = this.state.trackList[index-1 > 0 ? index - 1 : 0 ];
            this.setState({onPlayTrack:  track});
            this._initSelectedTrack(track);
        }
    }

    _nextTrack()
    {
        const index = this.state.trackList.indexOf(this.state.onPlayTrack);
        if (index === this.state.trackList.length)
        {
            alert("Now it is the lastest music");
        }
        else
        {
            const track = this.state.trackList[index + 1 > 0 ? index + 1 : 0 ];
            this.setState({ onPlayTrack: track });
            this._initSelectedTrack(track);
        }
    }

    _togglePlay()
    {
        if (!this.state.readyState) return ; //效果后续添加
        if (this.state.playState === true) {
            this.playStateBtn.classList.remove("icon-pause");
            this.playStateBtn.classList.add("icon-play");
            this.audio.pause();
            this.setState({playState : false});
        }
        else {
            this.playStateBtn.classList.remove("icon-play");
            this.playStateBtn.classList.add("icon-pause");
            this.audio.play();
            this.setState({playState : true});
        }
    }

    _initPlayer() {
        this.setState({playState: false});
        this.playStateBtn.classList.remove("icon-pause");
        this.playStateBtn.classList.add("icon-play");
        this.playingBar.style.width = "0px";
        this.processIcon.style.left = "0px";
    }

    _initSelectedTrack(track) {
        if (track) {
            let duration = 0;
            if (track.lMusic) {
                duration = track.lMusic.playTime;
            }
            else {
                duration = track.duration;
            }
            this.setState({
                onPlayTrack: track,
                playState: false,
                duration: "/" + TimeUtil.formateTime(duration),
                currentTime: "00:00",
                imgSrc: track.album.blurPicUrl,
                artistName: track.artists.map(artist => artist.name).join(","),
                trackName: track.name,
                mp3Url: track.mp3Url
            });
        }
        else {
            this.setState({
                onPlayTrack: null,
                playState: false,
                duration: "/00:00",
                currentTime: "00:00",
                imgSrc: "",
                artistName: "",
                trackName: "未知",
                mp3Url: ""
            });
        }
    }
    //歌曲进度控制，realSet为true时真实设置歌曲进度
     _processControl(offsetLeft, realSet = false) {
         let left = offsetLeft;
         let width = 0;

         if (left < 0) {
             left = 0;
         }
         else if (left > 492) {
             left = 492;
             width = 500;
         }
         else {
             width = left + 16;
         }

         this.processIcon.style.left = left + "px";
         this.playingBar.style.width = width + "px";

         if (realSet) {
             const currentTime = (Math.round(this.audio.duration * width / 500));
             this.audio.currentTime = currentTime;
         }
     }

     //歌曲声音控制，realSet为true时真实设置为歌曲声音
     _volumeControl(offsetLeft, realSet = false) {
         let left = offsetLeft;
         let width = 0;
         console.log(left);
         if (left < 0) {
             left = 0;
         }
         else if (left > 92) {
             left = 92;
             width = 100;
         }
         else {
             width = left + 8;
         }
         this.volumeIcon.style.left = left + "px";
         this.volumeBar.style.width = width + "px";

         if (realSet) {
             const volume = width / 100;
             this.audio.volume = volume;
         }
     }

     //开关音乐声音
     _toggleSound() {
         this.setState({
             muted: !this.state.muted
         });
     }

     //进度条点击事件监听器
     _handleProcess(e) {
         let processLeft = $('.track-process').offset().left;
         const left = e.clientX - processLeft - 8;
         this._processControl(left, true);
     }

     //声音条点击事件监听器
     _handleVolume(e) {
         let volumeLeft = $('.volume-process').offset().left;
         const left = e.clientX - volumeLeft - 8;
         this._volumeControl(left, true);
     }
}
<|endoftext|>


<commit_before>$(document).ready(function() {
	chrome.browserAction.setBadgeBackgroundColor({color: [255,0,0,255]});
	//chrome.browserAction.setBadgeText({text: "10"});
	var url = "http://www.reddit.com/r/";

    $.ajax({
        url: "http://www.reddit.com/r/ClassicOffensive/new.json",
        type: 'GET',
        dataType: 'json',
        beforeSend : function(xhr) {
            // xhr.setRequestHeader("Authorization", "Bearer " + token);
        },
        success: function(data, textStatus, jqXHR) {
			var count = 0;
			var posts = data.data.children;
            if(jqXHR.status == 200) {
				var number = 1;
				for(var i = 0; i < posts.length; i++){
					if(posts[i].data.clicked === false){
						count++;
						//dict["" + posts[i].data.title] = "" + posts[i].data.selftext;
						var $item = $("#post").clone();
						$item.find("#title").text("" + number++ + ") " + posts[i].data.title);
						if(posts[i].data.selftext_html !== null){
							$item.find("#text").text("" + posts[i].data.selftext.substring(0, 90) + "...");
						}
						$item.appendTo("#list");
					}
				}
            }
			chrome.browserAction.setBadgeText({text: "" + count});
        },
        error: function(jqXHR, textStatus, errorThrown) {
            // Reload the page if the server went down
            if(jqXHR.readyState == 0 && jqXHR.status == 0) {
                // REMOVE THIS
            }

            // Check for Unauthorized
            if(jqXHR.status == 401) {
                // REMOVE THIS
            }

            // Handle server 500
            if(jqXHR.status == 500) {
                // TODO
            }
        }
    });

});
<commit_msg>Divide url into variables<commit_after>$(document).ready(function() {
	chrome.browserAction.setBadgeBackgroundColor({color: [255,0,0,255]});
	//chrome.browserAction.setBadgeText({text: "10"});
	const base_url = "http://www.reddit.com/r/";
	var subreddit = "ClassicOffensive";
	var sorting = "new";

	var URL = base_url + subreddit + "/" + sorting + ".json";

    $.ajax({
				url: URL,
        type: 'GET',
        dataType: 'json',
        beforeSend : function(xhr) {
            // xhr.setRequestHeader("Authorization", "Bearer " + token);
        },
        success: function(data, textStatus, jqXHR) {
			var count = 0;
			var posts = data.data.children;
            if(jqXHR.status == 200) {
				var number = 1;
				for(var i = 0; i < posts.length; i++){
					if(posts[i].data.clicked === false){
						count++;
						//dict["" + posts[i].data.title] = "" + posts[i].data.selftext;
						var $item = $("#post").clone();
						$item.find("#title").text("" + number++ + ") " + posts[i].data.title);
						if(posts[i].data.selftext_html !== null){
							$item.find("#text").text("" + posts[i].data.selftext.substring(0, 90) + "...");
						}
						$item.appendTo("#list");
					}
				}
            }
			chrome.browserAction.setBadgeText({text: "" + count});
        },
        error: function(jqXHR, textStatus, errorThrown) {
            // Reload the page if the server went down
            if(jqXHR.readyState == 0 && jqXHR.status == 0) {
                // REMOVE THIS
            }

            // Check for Unauthorized
            if(jqXHR.status == 401) {
                // REMOVE THIS
            }

            // Handle server 500
            if(jqXHR.status == 500) {
                // TODO
            }
        }
    });

});
<|endoftext|>


<commit_before>// favorite-object-api-test.js
//
// Test favoriting a posted object
//
// Copyright 2012, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var assert = require('assert'),
    vows = require('vows'),
    Step = require('step'),
    _ = require('underscore'),
    OAuth = require('oauth').OAuth,
    httputil = require('./lib/http'),
    oauthutil = require('./lib/oauth'),
    actutil = require('./lib/activity'),
    setupApp = oauthutil.setupApp,
    newClient = oauthutil.newClient,
    newPair = oauthutil.newPair;

var ignore = function(err) {};
var makeCred = function(cl, pair) {
    return {
        consumer_key: cl.client_id,
        consumer_secret: cl.client_secret,
        token: pair.token,
        token_secret: pair.token_secret
    };
};

var assertValidList = function(doc, count) {
    assert.include(doc, 'author');
    assert.include(doc.author, 'id');
    assert.include(doc.author, 'displayName');
    assert.include(doc.author, 'objectType');
    assert.include(doc, 'totalItems');
    assert.include(doc, 'items');
    assert.include(doc, 'displayName');
    assert.include(doc, 'id');
    if (_(count).isNumber()) {
        assert.equal(doc.totalItems, count);
        assert.lengthOf(doc.items, count);
    }
};

var suite = vows.describe('favorite object activity api test');

// A batch to test following/unfollowing users

suite.addBatch({
    'When we set up the app': {
        topic: function() {
            setupApp(this.callback);
        },
        teardown: function(app) {
            if (app && app.close) {
                app.close();
            }
        },
        'it works': function(err, app) {
            assert.ifError(err);
        },
        'and we register a client': {
            topic: function() {
                newClient(this.callback);
            },
            'it works': function(err, cl) {
                assert.ifError(err);
                assert.isObject(cl);
            },
            'and we get the list of favorites for a new user': {
                topic: function(cl) {
                    var cb = this.callback;
                    Step(
                        function() {
                            newPair(cl, "marsha", "hair", this);
                        },
                        function(err, pair) {
                            if (err) throw err;
                            var cred = makeCred(cl, pair),
                                url = 'http://localhost:4815/api/user/marsha/favorites';

                            httputil.getJSON(url, cred, this);
                        },
                        function(err, doc, response) {
                            cb(err, doc);
                        }
                    );
                },
                'it exists': function(err, doc) {
                    assert.ifError(err);
                },
                'it looks correct': function(err, doc) {
                    assert.ifError(err);
                    assertValidList(doc, 0);
                }
            },
            'and we get the list of favorites for a brand-new object': {
                topic: function(cl) {
                    var cb = this.callback,
                        cred;
                    Step(
                        function() {
                            newPair(cl, "jan", "marsha", this);
                        },
                        function(err, pair) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/jan/feed',
                                act = {
                                    verb: "post",
                                    object: {
                                        objectType: "note",
                                        content: "MARSHA MARSHA MARSHA"
                                    }
                                };

                            cred = makeCred(cl, pair);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = doc.object.likes.url;
                            httputil.getJSON(url, cred, this);
                        },
                        function(err, doc, response) {
                            cb(err, doc);
                        }
                    );
                },
                'it exists': function(err, faves) {
                    assert.ifError(err);
                },
                'it is empty': function(err, faves) {
                    assert.ifError(err);
                    assertValidList(faves, 0);
                }
            },
            'and one user favorites another user\'s object': {
                topic: function(cl) {
                    var cb = this.callback,
                        pairs = {};

                    Step(
                        function() {
                            newPair(cl, "cindy", "pigtails", this.parallel());
                            newPair(cl, "bobby", "baseball", this.parallel());
                        },
                        function(err, cpair, bpair) {
                            if (err) throw err;
                            pairs.cindy = cpair;
                            pairs.bobby = bpair;

                            var url = 'http://localhost:4815/api/user/cindy/feed',
                                act = {
                                    verb: "post",
                                    object: {
                                        objectType: "note",
                                        content: "Let's play dress-up."
                                    }
                                };

                            var cred = makeCred(cl, pairs.cindy);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/bobby/feed',
                                act = {
                                    verb: "favorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.bobby);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            cb(err, doc, pairs);
                        }
                    );
                },
                'it works': function(err, act, pairs) {
                    assert.ifError(err);
                },
                'and we get the user\'s list of favorites': {
                    topic: function(act, pairs, cl) {
                        var cred = makeCred(cl, pairs.bobby),
                            url = 'http://localhost:4815/api/user/bobby/favorites',
                            cb = this.callback;

                            httputil.getJSON(url, cred, function(err, doc, response) {
                                cb(err, doc, act);
                            });
                    },
                    'it works': function(err, doc, act) {
                        assert.ifError(err);
                        assertValidList(doc, 1);
                    },
                    'it includes the object': function(err, doc, act) {
                        assert.ifError(err);
                        assert.equal(doc.items[0].id, act.object.id);
                    }
                },
                'and we get the list of likes of the object': {
                    topic: function(act, pairs, cl) {
                        var cred = makeCred(cl, pairs.cindy),
                            url = act.object.likes.url,
                            cb = this.callback;

                            httputil.getJSON(url, cred, function(err, doc, response) {
                                cb(err, doc, act);
                            });
                    },
                    'it works': function(err, doc, act) {
                        assert.ifError(err);
                        assertValidList(doc, 1);
                    },
                    'it includes the actor': function(err, doc, act) {
                        assert.ifError(err);
                        assert.equal(doc.items[0].id, act.actor.id);
                    }
                }
            },
            'and one user double-favorites another user\'s object': {
                topic: function(cl) {
                    var cb = this.callback,
                        pairs = {};

                    Step(
                        function() {
                            newPair(cl, "alice", "backpain", this.parallel());
                            newPair(cl, "sam", "alice", this.parallel());
                        },
                        function(err, apair, spair) {
                            if (err) throw err;
                            pairs.alice = apair;
                            pairs.sam = spair;

                            var url = 'http://localhost:4815/api/user/alice/feed',
                                act = {
                                    verb: "post",
                                    object: {
                                        objectType: "note",
                                        content: "Pot roast tonight."
                                    }
                                };

                            var cred = makeCred(cl, pairs.alice);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/sam/feed',
                                act = {
                                    verb: "favorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.sam);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/sam/feed',
                                act = {
                                    verb: "favorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.sam);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err && err.statusCode && err.statusCode >= 400 && err.statusCode < 500) {
                                cb(null);
                            } else if (err) {
                                cb(err);
                            } else {
                                cb(new Error("Unexpected success"));
                            }
                        }
                    );
                },
                'it fails correctly': function(err) {
                    assert.ifError(err);
                }
            },
            'and one user favorites then unfavorites another user\'s object': {
                topic: function(cl) {
                    var cb = this.callback,
                        pairs = {};

                    Step(
                        function() {
                            newPair(cl, "greg", "groovy", this.parallel());
                            newPair(cl, "peter", "vengeance", this.parallel());
                        },
                        function(err, gpair, ppair) {
                            if (err) throw err;
                            pairs.greg = gpair;
                            pairs.peter = ppair;

                            var url = 'http://localhost:4815/api/user/peter/feed',
                                act = {
                                    verb: "post",
                                    object: {
                                        objectType: "note",
                                        content: "I'm going to build a fort."
                                    }
                                };

                            var cred = makeCred(cl, pairs.peter);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/greg/feed',
                                act = {
                                    verb: "favorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.greg);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/greg/feed',
                                act = {
                                    verb: "unfavorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.greg);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            cb(err, doc);
                        }
                    );
                },
                'it works': function(err, act) {
                    assert.ifError(err);
                },
                'and we get the user\'s list of favorites': {
                    topic: function(act, pairs, cl) {
                        var cred = makeCred(cl, pairs.greg),
                            url = 'http://localhost:4815/api/user/greg/favorites',
                            cb = this.callback;

                            httputil.getJSON(url, cred, function(err, doc, response) {
                                cb(err, doc, act);
                            });
                    },
                    'it works': function(err, doc, act) {
                        assert.ifError(err);
                        assertValidList(doc, 0);
                    }
                },
                'and we get the list of favorites of the object': {
                    topic: function(act, pairs, cl) {
                        var cred = makeCred(cl, pairs.peter),
                            url = act.object.likes.url,
                            cb = this.callback;

                            httputil.getJSON(url, cred, function(err, doc, response) {
                                cb(err, doc);
                            });
                    },
                    'it works': function(err, doc) {
                        assert.ifError(err);
                        assertValidList(doc, 0);
                    }
                }
            },
            'and one user unfavorites another user\'s object they hadn\'t faved before': {
                topic: function(cl) {
                    var cb = this.callback,
                        pairs = {};

                    Step(
                        function() {
                            newPair(cl, "mike", "arch1tecture", this.parallel());
                            newPair(cl, "carol", "mike", this.parallel());
                        },
                        function(err, mpair, cpair) {
                            if (err) throw err;
                            pairs.mike = mpair;
                            pairs.carol = cpair;

                            var url = 'http://localhost:4815/api/user/mike/feed',
                                act = {
                                    verb: "post",
                                    object: {
                                        objectType: "note",
                                        content: "We're going to Hawaii!"
                                    }
                                };

                            var cred = makeCred(cl, pairs.mike);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/carol/feed',
                                act = {
                                    verb: "unfavorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.carol);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err && err.statusCode && err.statusCode >= 400 && err.statusCode < 500) {
                                cb(null);
                            } else if (err) {
                                cb(err);
                            } else {
                                cb(new Error("Unexpected success"));
                            }
                        }
                    );
                },
                'it fails correctly': function(err) {
                    assert.ifError(err);
                }
            },
            'and one user favorites an unknown or arbitrary object': {
                topic: function(cl) {
                    var cb = this.callback,
                        pairs = {};

                    Step(
                        function() {
                            newPair(cl, "tiger", "fleapowder", this);
                        },
                        function(err, pair) {
                            if (err) throw err;
                            pairs.tiger = pair;

                            var url = 'http://localhost:4815/api/user/tiger/feed',
                                act = {
                                    verb: "favorite",
                                    object: {
                                        objectType: "image",
                                        id: "urn:uuid:30b3f9aa-6e20-4e2a-8325-b72cfbccb4d0"
                                    }
                                };

                            var cred = makeCred(cl, pairs.tiger);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            cb(err, doc);
                        }
                    );
                },
                'it works': function(err, act) {
                    assert.ifError(err);
                },
                'and we get the user\'s list of favorites': {
                    topic: function(act, pairs, cl) {
                        var cred = makeCred(cl, pairs.tiger),
                            url = 'http://localhost:4815/api/user/tiger/favorites',
                            cb = this.callback;

                        httputil.getJSON(url, cred, function(err, doc, response) {
                            cb(err, doc, act);
                        });
                    },
                    'it works': function(err, doc, act) {
                        assert.ifError(err);
                        assertValidList(doc, 1);
                    },
                    'it includes our object': function(err, doc, act) {
                        assert.ifError(err);
                        assert.equal(doc.items[0].id, act.object.id);
                    }
                }
            }
        }
    }
});

suite['export'](module);
<commit_msg>Don't look for author on favorites of an object<commit_after>// favorite-object-api-test.js
//
// Test favoriting a posted object
//
// Copyright 2012, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var assert = require('assert'),
    vows = require('vows'),
    Step = require('step'),
    _ = require('underscore'),
    OAuth = require('oauth').OAuth,
    httputil = require('./lib/http'),
    oauthutil = require('./lib/oauth'),
    actutil = require('./lib/activity'),
    setupApp = oauthutil.setupApp,
    newClient = oauthutil.newClient,
    newPair = oauthutil.newPair;

var ignore = function(err) {};
var makeCred = function(cl, pair) {
    return {
        consumer_key: cl.client_id,
        consumer_secret: cl.client_secret,
        token: pair.token,
        token_secret: pair.token_secret
    };
};

var assertValidList = function(doc, count) {
    assert.include(doc, 'author');
    assert.include(doc.author, 'id');
    assert.include(doc.author, 'displayName');
    assert.include(doc.author, 'objectType');
    assert.include(doc, 'totalItems');
    assert.include(doc, 'items');
    assert.include(doc, 'displayName');
    assert.include(doc, 'id');
    if (_(count).isNumber()) {
        assert.equal(doc.totalItems, count);
        assert.lengthOf(doc.items, count);
    }
};

var suite = vows.describe('favorite object activity api test');

// A batch to test following/unfollowing users

suite.addBatch({
    'When we set up the app': {
        topic: function() {
            setupApp(this.callback);
        },
        teardown: function(app) {
            if (app && app.close) {
                app.close();
            }
        },
        'it works': function(err, app) {
            assert.ifError(err);
        },
        'and we register a client': {
            topic: function() {
                newClient(this.callback);
            },
            'it works': function(err, cl) {
                assert.ifError(err);
                assert.isObject(cl);
            },
            'and we get the list of favorites for a new user': {
                topic: function(cl) {
                    var cb = this.callback;
                    Step(
                        function() {
                            newPair(cl, "marsha", "hair", this);
                        },
                        function(err, pair) {
                            if (err) throw err;
                            var cred = makeCred(cl, pair),
                                url = 'http://localhost:4815/api/user/marsha/favorites';

                            httputil.getJSON(url, cred, this);
                        },
                        function(err, doc, response) {
                            cb(err, doc);
                        }
                    );
                },
                'it exists': function(err, doc) {
                    assert.ifError(err);
                },
                'it looks correct': function(err, doc) {
                    assert.ifError(err);
                    assertValidList(doc, 0);
                }
            },
            'and we get the list of favorites for a brand-new object': {
                topic: function(cl) {
                    var cb = this.callback,
                        cred;
                    Step(
                        function() {
                            newPair(cl, "jan", "marsha", this);
                        },
                        function(err, pair) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/jan/feed',
                                act = {
                                    verb: "post",
                                    object: {
                                        objectType: "note",
                                        content: "MARSHA MARSHA MARSHA"
                                    }
                                };

                            cred = makeCred(cl, pair);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = doc.object.likes.url;
                            httputil.getJSON(url, cred, this);
                        },
                        function(err, doc, response) {
                            cb(err, doc);
                        }
                    );
                },
                'it exists': function(err, faves) {
                    assert.ifError(err);
                },
                'it is empty': function(err, faves) {
                    assert.ifError(err);
                    assert.include(faves, 'totalCount');
                    assert.include(faves, 'items');
                    assert.include(faves, 'displayName');
                    assert.include(faves, 'id');
                    assert.equal(faves.totalCount, 0);
                    assert.lengthOf(faves.items, 0);
                }
            },
            'and one user favorites another user\'s object': {
                topic: function(cl) {
                    var cb = this.callback,
                        pairs = {};

                    Step(
                        function() {
                            newPair(cl, "cindy", "pigtails", this.parallel());
                            newPair(cl, "bobby", "baseball", this.parallel());
                        },
                        function(err, cpair, bpair) {
                            if (err) throw err;
                            pairs.cindy = cpair;
                            pairs.bobby = bpair;

                            var url = 'http://localhost:4815/api/user/cindy/feed',
                                act = {
                                    verb: "post",
                                    object: {
                                        objectType: "note",
                                        content: "Let's play dress-up."
                                    }
                                };

                            var cred = makeCred(cl, pairs.cindy);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/bobby/feed',
                                act = {
                                    verb: "favorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.bobby);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            cb(err, doc, pairs);
                        }
                    );
                },
                'it works': function(err, act, pairs) {
                    assert.ifError(err);
                },
                'and we get the user\'s list of favorites': {
                    topic: function(act, pairs, cl) {
                        var cred = makeCred(cl, pairs.bobby),
                            url = 'http://localhost:4815/api/user/bobby/favorites',
                            cb = this.callback;

                            httputil.getJSON(url, cred, function(err, doc, response) {
                                cb(err, doc, act);
                            });
                    },
                    'it works': function(err, doc, act) {
                        assert.ifError(err);
                        assertValidList(doc, 1);
                    },
                    'it includes the object': function(err, doc, act) {
                        assert.ifError(err);
                        assert.equal(doc.items[0].id, act.object.id);
                    }
                },
                'and we get the list of likes of the object': {
                    topic: function(act, pairs, cl) {
                        var cred = makeCred(cl, pairs.cindy),
                            url = act.object.likes.url,
                            cb = this.callback;

                            httputil.getJSON(url, cred, function(err, doc, response) {
                                cb(err, doc, act);
                            });
                    },
                    'it works': function(err, doc, act) {
                        assert.ifError(err);
                        assert.include(doc, 'totalCount');
                        assert.include(doc, 'items');
                        assert.include(doc, 'displayName');
                        assert.include(doc, 'id');
                        assert.equal(doc.totalCount, 1);
                        assert.lengthOf(doc.items, 1);
                    },
                    'it includes the actor': function(err, doc, act) {
                        assert.ifError(err);
                        assert.equal(doc.items[0].id, act.actor.id);
                    }
                }
            },
            'and one user double-favorites another user\'s object': {
                topic: function(cl) {
                    var cb = this.callback,
                        pairs = {};

                    Step(
                        function() {
                            newPair(cl, "alice", "backpain", this.parallel());
                            newPair(cl, "sam", "alice", this.parallel());
                        },
                        function(err, apair, spair) {
                            if (err) throw err;
                            pairs.alice = apair;
                            pairs.sam = spair;

                            var url = 'http://localhost:4815/api/user/alice/feed',
                                act = {
                                    verb: "post",
                                    object: {
                                        objectType: "note",
                                        content: "Pot roast tonight."
                                    }
                                };

                            var cred = makeCred(cl, pairs.alice);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/sam/feed',
                                act = {
                                    verb: "favorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.sam);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/sam/feed',
                                act = {
                                    verb: "favorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.sam);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err && err.statusCode && err.statusCode >= 400 && err.statusCode < 500) {
                                cb(null);
                            } else if (err) {
                                cb(err);
                            } else {
                                cb(new Error("Unexpected success"));
                            }
                        }
                    );
                },
                'it fails correctly': function(err) {
                    assert.ifError(err);
                }
            },
            'and one user favorites then unfavorites another user\'s object': {
                topic: function(cl) {
                    var cb = this.callback,
                        pairs = {};

                    Step(
                        function() {
                            newPair(cl, "greg", "groovy", this.parallel());
                            newPair(cl, "peter", "vengeance", this.parallel());
                        },
                        function(err, gpair, ppair) {
                            if (err) throw err;
                            pairs.greg = gpair;
                            pairs.peter = ppair;

                            var url = 'http://localhost:4815/api/user/peter/feed',
                                act = {
                                    verb: "post",
                                    object: {
                                        objectType: "note",
                                        content: "I'm going to build a fort."
                                    }
                                };

                            var cred = makeCred(cl, pairs.peter);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/greg/feed',
                                act = {
                                    verb: "favorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.greg);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/greg/feed',
                                act = {
                                    verb: "unfavorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.greg);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            cb(err, doc);
                        }
                    );
                },
                'it works': function(err, act) {
                    assert.ifError(err);
                },
                'and we get the user\'s list of favorites': {
                    topic: function(act, pairs, cl) {
                        var cred = makeCred(cl, pairs.greg),
                            url = 'http://localhost:4815/api/user/greg/favorites',
                            cb = this.callback;

                            httputil.getJSON(url, cred, function(err, doc, response) {
                                cb(err, doc, act);
                            });
                    },
                    'it works': function(err, doc, act) {
                        assert.ifError(err);
                        assertValidList(doc, 0);
                    }
                },
                'and we get the list of favorites of the object': {
                    topic: function(act, pairs, cl) {
                        var cred = makeCred(cl, pairs.peter),
                            url = act.object.likes.url,
                            cb = this.callback;

                            httputil.getJSON(url, cred, function(err, doc, response) {
                                cb(err, doc);
                            });
                    },
                    'it works': function(err, doc) {
                        assert.ifError(err);
                        assert.include(doc, 'totalCount');
                        assert.include(doc, 'items');
                        assert.include(doc, 'displayName');
                        assert.include(doc, 'id');
                        assert.equal(doc.totalCount, 0);
                        assert.lengthOf(doc.items, 0);
                    }
                }
            },
            'and one user unfavorites another user\'s object they hadn\'t faved before': {
                topic: function(cl) {
                    var cb = this.callback,
                        pairs = {};

                    Step(
                        function() {
                            newPair(cl, "mike", "arch1tecture", this.parallel());
                            newPair(cl, "carol", "mike", this.parallel());
                        },
                        function(err, mpair, cpair) {
                            if (err) throw err;
                            pairs.mike = mpair;
                            pairs.carol = cpair;

                            var url = 'http://localhost:4815/api/user/mike/feed',
                                act = {
                                    verb: "post",
                                    object: {
                                        objectType: "note",
                                        content: "We're going to Hawaii!"
                                    }
                                };

                            var cred = makeCred(cl, pairs.mike);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err) throw err;
                            var url = 'http://localhost:4815/api/user/carol/feed',
                                act = {
                                    verb: "unfavorite",
                                    object: {
                                        objectType: doc.object.objectType,
                                        id: doc.object.id
                                    }
                                },
                                cred = makeCred(cl, pairs.carol);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            if (err && err.statusCode && err.statusCode >= 400 && err.statusCode < 500) {
                                cb(null);
                            } else if (err) {
                                cb(err);
                            } else {
                                cb(new Error("Unexpected success"));
                            }
                        }
                    );
                },
                'it fails correctly': function(err) {
                    assert.ifError(err);
                }
            },
            'and one user favorites an unknown or arbitrary object': {
                topic: function(cl) {
                    var cb = this.callback,
                        pairs = {};

                    Step(
                        function() {
                            newPair(cl, "tiger", "fleapowder", this);
                        },
                        function(err, pair) {
                            if (err) throw err;
                            pairs.tiger = pair;

                            var url = 'http://localhost:4815/api/user/tiger/feed',
                                act = {
                                    verb: "favorite",
                                    object: {
                                        objectType: "image",
                                        id: "urn:uuid:30b3f9aa-6e20-4e2a-8325-b72cfbccb4d0"
                                    }
                                };

                            var cred = makeCred(cl, pairs.tiger);

                            httputil.postJSON(url, cred, act, this);
                        },
                        function(err, doc, response) {
                            cb(err, doc);
                        }
                    );
                },
                'it works': function(err, act) {
                    assert.ifError(err);
                },
                'and we get the user\'s list of favorites': {
                    topic: function(act, pairs, cl) {
                        var cred = makeCred(cl, pairs.tiger),
                            url = 'http://localhost:4815/api/user/tiger/favorites',
                            cb = this.callback;

                        httputil.getJSON(url, cred, function(err, doc, response) {
                            cb(err, doc, act);
                        });
                    },
                    'it works': function(err, doc, act) {
                        assert.ifError(err);
                        assertValidList(doc, 1);
                    },
                    'it includes our object': function(err, doc, act) {
                        assert.ifError(err);
                        assert.equal(doc.items[0].id, act.object.id);
                    }
                }
            }
        }
    }
});

suite['export'](module);
<|endoftext|>