<commit_before>'use strict'

var util = require('util')
var express = require('express')
  , should = require('should')
  , qs = require('qs')
var Grant = require('../../').express()
  , oauth1 = require('../../lib/flow/oauth1')

describe('oauth1', function () {
  function url (path) {
    var c = config.server
    return c.protocol + '://' + c.host + path
  }

  var grant, app, server
  var config = {
    server: {protocol:'http', host:'localhost:5000', callback:'/'},
    twitter:{}
  }

  describe('success', function () {
    before(function (done) {
      grant = new Grant(config)
      app = express().use(grant)

      grant.config.twitter.request_url = url('/request_url')
      grant.config.twitter.authorize_url = '/authorize_url'
      grant.config.twitter.access_url = url('/access_url')

      app.post('/request_url', function (req, res) {
        res.end(qs.stringify({some:'data'}))
      })
      app.post('/access_url', function (req, res) {
        res.end(JSON.stringify({some:'data'}))
      })
      server = app.listen(5000, done)
    })

    it('step1', function (done) {
      oauth1.step1(grant.config.twitter, function (err, data) {
        should.deepEqual(data, {some:'data'})
        done()
      })
    })

    it('step2', function () {
      var url = oauth1.step2(grant.config.twitter, {oauth_token:'token'})
      url.should.equal('/authorize_url?oauth_token=token')
    })

    it('step3', function (done) {
      oauth1.step3(grant.config.twitter, {}, {oauth_token:'token'}, function (err, url) {
        url.should.equal('raw%5Bsome%5D=data')
        done()
      })
    })

    after(function (done) {
      server.close(done)
    })
  })

  describe('error', function () {
    before(function (done) {
      grant = new Grant(config)
      app = express().use(grant)

      grant.config.twitter.request_url = url('/request_err')
      grant.config.twitter.authorize_url = '/authorize_url'
      grant.config.twitter.access_url = url('/access_url')

      app.post('/request_url', function (req, res) {
        res.status(500).end(JSON.stringify({error:'invalid'}))
      })

      server = app.listen(5000, done)
    })

    it('step1 - network error', function (done) {
      oauth1.step1(grant.config.twitter, function (err, body) {
        should.deepEqual(qs.parse(err), {error: {'Cannot POST /request_err\n': ''}})
        done()
      })
    })
    it('step1 - error response', function (done) {
      grant.config.twitter.request_url = url('/request_url')
      oauth1.step1(grant.config.twitter, function (err, body) {
        should.deepEqual(qs.parse(err), {error: {error:'invalid'}})
        done()
      })
    })

    it('step2 - mising oauth_token - error response', function () {
      var url = oauth1.step2(grant.config.twitter, {error:'invalid'})
      should.deepEqual(qs.parse(url.replace('/?','')),
        {error: {error:'invalid'}})
    })
    it('step2 - mising oauth_token - empty response', function () {
      var url = oauth1.step2(grant.config.twitter, {})
      should.deepEqual(qs.parse(url.replace('/?','')),
        {error: {error:'Grant: OAuth1 missing oauth_token parameter'}})
    })

    it('step3 - mising oauth_token - response error', function (done) {
      oauth1.step3(grant.config.twitter, {}, {error:'invalid'}, function (err, body) {
        should.deepEqual(qs.parse(err), {error: {error:'invalid'}})
        done()
      })
    })
    it('step3 - mising oauth_token - empty response', function (done) {
      oauth1.step3(grant.config.twitter, {}, {}, function (err, body) {
        should.deepEqual(qs.parse(err),
          {error: {error:'Grant: OAuth1 missing oauth_token parameter'}})
        done()
      })
    })

    after(function (done) {
      server.close(done)
    })
  })

  describe('custom', function () {
    describe('step1', function () {
      before(function (done) {
        util._extend(config, {
          copy:{}, etsy:{}, flickr:{}, freshbooks:{}, goodreads:{},
          linkedin:{}, trello:{}, tripit:{}
        })
        grant = new Grant(config)
        app = express().use(grant)

        app.post('/request_url', function (req, res) {
          res.end(qs.stringify({oauth:req.headers.authorization, scope:req.query.scope}))
        })
        server = app.listen(5000, done)
      })

      describe('querystring scope', function () {
        it('copy', function (done) {
          grant.config.copy.request_url = url('/request_url')
          grant.config.copy.scope = '{"profile":{"read":true}}'
          oauth1.step1(grant.config.copy, function (err, body) {
            body.scope.should.equal('{"profile":{"read":true}}')
            done()
          })
        })
        it('etsy', function (done) {
          grant.config.etsy.request_url = url('/request_url')
          grant.config.etsy.scope = 'email_r profile_r'
          oauth1.step1(grant.config.etsy, function (err, body) {
            body.scope.should.equal('email_r profile_r')
            done()
          })
        })
        it('linkedin', function (done) {
          grant.config.linkedin.request_url = url('/request_url')
          grant.config.linkedin.scope = 'scope1,scope2'
          oauth1.step1(grant.config.linkedin, function (err, body) {
            body.scope.should.equal('scope1,scope2')
            done()
          })
        })
      })

      describe('signature_method', function () {
        it('freshbooks', function (done) {
          grant.config.freshbooks.request_url = url('/request_url')
          oauth1.step1(grant.config.freshbooks, function (err, body) {
            body.oauth.should.match(/oauth_signature_method="PLAINTEXT"/)
            done()
          })
        })
      })

      describe('subdomain', function () {
        it('freshbooks', function (done) {
          grant.config.freshbooks.request_url = url('/[subdomain]')
          grant.config.freshbooks.subdomain = 'request_url'
          oauth1.step1(grant.config.freshbooks, function (err, body) {
            body.oauth.should.match(/OAuth/)
            done()
          })
        })
      })

      after(function (done) {
        server.close(done)
      })
    })

    describe('step2', function () {
      before(function () {
        grant = new Grant(config)
      })

      describe('custom_params', function () {
        it('flickr', function () {
          grant.config.flickr.scope = ['read','write']
          var url = oauth1.step2(grant.config.flickr, {oauth_token:'token'})
          var query = qs.parse(url.split('?')[1])
          should.deepEqual(query,
            {oauth_token:'token', perms:['read','write']})
        })

        it('trello', function () {
          grant.config.trello.custom_params = {expiration:'never', name:'Grant'}
          grant.config.trello.scope = ['read','write']
          var url = oauth1.step2(grant.config.trello, {oauth_token:'token'})
          var query = qs.parse(url.split('?')[1])
          should.deepEqual(query,
            {oauth_token:'token', scope:['read','write'], expiration:'never', name:'Grant'})
        })
      })

      describe('subdomain', function () {
        it('freshbooks', function () {
          grant.config.freshbooks.subdomain = 'grant'
          var url = oauth1.step2(grant.config.freshbooks, {oauth_token:'token'})
          url.indexOf('https://grant.freshbooks.com').should.equal(0)
        })
      })

      describe('oauth_callback', function () {
        it('tripit', function () {
          var uri = oauth1.step2(grant.config.tripit, {oauth_token:'token'})
          var query = qs.parse(uri.split('?')[1])
          should.deepEqual(query,
            {oauth_token:'token', oauth_callback:url('/connect/tripit/callback')})
        })
      })
    })

    describe('step3', function () {
      before(function (done) {
        grant = new Grant(config)
        app = express().use(grant)

        app.post('/access_url', function (req, res) {
          res.end(qs.stringify({oauth:req.headers.authorization}))
        })
        server = app.listen(5000, done)
      })

      describe('signature_method', function () {
        it('freshbooks', function (done) {
          grant.config.freshbooks.access_url = url('/access_url')
          oauth1.step3(grant.config.freshbooks, {}, {oauth_token:'token'}, function (err, response) {
            var query = qs.parse(response)
            query.raw.oauth.should.match(/oauth_signature_method="PLAINTEXT"/)
            done()
          })
        })
      })

      describe('oauth_verifier', function () {
        it('goodreads', function (done) {
          grant.config.goodreads.access_url = url('/access_url')
          oauth1.step3(grant.config.goodreads, {}, {oauth_token:'token'}, function (err, response) {
            var query = qs.parse(response)
            query.raw.oauth.should.not.match(/verifier/)
            done()
          })
        })
        it('tripit', function (done) {
          grant.config.tripit.access_url = url('/access_url')
          oauth1.step3(grant.config.tripit, {}, {oauth_token:'token'}, function (err, response) {
            var query = qs.parse(response)
            query.raw.oauth.should.not.match(/verifier/)
            done()
          })
        })
      })

      describe('subdomain', function () {
        it('freshbooks', function (done) {
          grant.config.freshbooks.access_url = url('/[subdomain]')
          grant.config.freshbooks.subdomain = 'access_url'
          oauth1.step3(grant.config.freshbooks, {}, {oauth_token:'token'}, function (err, url) {
            url.should.be.type('string')
            done()
          })
        })
      })

      after(function (done) {
        server.close(done)
      })
    })
  })
})
<commit_msg>Add ravelry scope test<commit_after>'use strict'

var util = require('util')
var express = require('express')
  , should = require('should')
  , qs = require('qs')
var Grant = require('../../').express()
  , oauth1 = require('../../lib/flow/oauth1')

describe('oauth1', function () {
  function url (path) {
    var c = config.server
    return c.protocol + '://' + c.host + path
  }

  var grant, app, server
  var config = {
    server: {protocol:'http', host:'localhost:5000', callback:'/'},
    twitter:{}
  }

  describe('success', function () {
    before(function (done) {
      grant = new Grant(config)
      app = express().use(grant)

      grant.config.twitter.request_url = url('/request_url')
      grant.config.twitter.authorize_url = '/authorize_url'
      grant.config.twitter.access_url = url('/access_url')

      app.post('/request_url', function (req, res) {
        res.end(qs.stringify({some:'data'}))
      })
      app.post('/access_url', function (req, res) {
        res.end(JSON.stringify({some:'data'}))
      })
      server = app.listen(5000, done)
    })

    it('step1', function (done) {
      oauth1.step1(grant.config.twitter, function (err, data) {
        should.deepEqual(data, {some:'data'})
        done()
      })
    })

    it('step2', function () {
      var url = oauth1.step2(grant.config.twitter, {oauth_token:'token'})
      url.should.equal('/authorize_url?oauth_token=token')
    })

    it('step3', function (done) {
      oauth1.step3(grant.config.twitter, {}, {oauth_token:'token'}, function (err, url) {
        url.should.equal('raw%5Bsome%5D=data')
        done()
      })
    })

    after(function (done) {
      server.close(done)
    })
  })

  describe('error', function () {
    before(function (done) {
      grant = new Grant(config)
      app = express().use(grant)

      grant.config.twitter.request_url = url('/request_err')
      grant.config.twitter.authorize_url = '/authorize_url'
      grant.config.twitter.access_url = url('/access_url')

      app.post('/request_url', function (req, res) {
        res.status(500).end(JSON.stringify({error:'invalid'}))
      })

      server = app.listen(5000, done)
    })

    it('step1 - network error', function (done) {
      oauth1.step1(grant.config.twitter, function (err, body) {
        should.deepEqual(qs.parse(err), {error: {'Cannot POST /request_err\n': ''}})
        done()
      })
    })
    it('step1 - error response', function (done) {
      grant.config.twitter.request_url = url('/request_url')
      oauth1.step1(grant.config.twitter, function (err, body) {
        should.deepEqual(qs.parse(err), {error: {error:'invalid'}})
        done()
      })
    })

    it('step2 - mising oauth_token - error response', function () {
      var url = oauth1.step2(grant.config.twitter, {error:'invalid'})
      should.deepEqual(qs.parse(url.replace('/?','')),
        {error: {error:'invalid'}})
    })
    it('step2 - mising oauth_token - empty response', function () {
      var url = oauth1.step2(grant.config.twitter, {})
      should.deepEqual(qs.parse(url.replace('/?','')),
        {error: {error:'Grant: OAuth1 missing oauth_token parameter'}})
    })

    it('step3 - mising oauth_token - response error', function (done) {
      oauth1.step3(grant.config.twitter, {}, {error:'invalid'}, function (err, body) {
        should.deepEqual(qs.parse(err), {error: {error:'invalid'}})
        done()
      })
    })
    it('step3 - mising oauth_token - empty response', function (done) {
      oauth1.step3(grant.config.twitter, {}, {}, function (err, body) {
        should.deepEqual(qs.parse(err),
          {error: {error:'Grant: OAuth1 missing oauth_token parameter'}})
        done()
      })
    })

    after(function (done) {
      server.close(done)
    })
  })

  describe('custom', function () {
    describe('step1', function () {
      before(function (done) {
        util._extend(config, {
          copy:{}, etsy:{}, flickr:{}, freshbooks:{}, goodreads:{},
          linkedin:{}, ravelry:{}, trello:{}, tripit:{}
        })
        grant = new Grant(config)
        app = express().use(grant)

        app.post('/request_url', function (req, res) {
          res.end(qs.stringify({oauth:req.headers.authorization, scope:req.query.scope}))
        })
        server = app.listen(5000, done)
      })

      describe('querystring scope', function () {
        it('copy', function (done) {
          grant.config.copy.request_url = url('/request_url')
          grant.config.copy.scope = '{"profile":{"read":true}}'
          oauth1.step1(grant.config.copy, function (err, body) {
            body.scope.should.equal('{"profile":{"read":true}}')
            done()
          })
        })
        it('etsy', function (done) {
          grant.config.etsy.request_url = url('/request_url')
          grant.config.etsy.scope = 'email_r profile_r'
          oauth1.step1(grant.config.etsy, function (err, body) {
            body.scope.should.equal('email_r profile_r')
            done()
          })
        })
        it('linkedin', function (done) {
          grant.config.linkedin.request_url = url('/request_url')
          grant.config.linkedin.scope = 'scope1,scope2'
          oauth1.step1(grant.config.linkedin, function (err, body) {
            body.scope.should.equal('scope1,scope2')
            done()
          })
        })
      })

      describe('signature_method', function () {
        it('freshbooks', function (done) {
          grant.config.freshbooks.request_url = url('/request_url')
          oauth1.step1(grant.config.freshbooks, function (err, body) {
            body.oauth.should.match(/oauth_signature_method="PLAINTEXT"/)
            done()
          })
        })
      })

      describe('subdomain', function () {
        it('freshbooks', function (done) {
          grant.config.freshbooks.request_url = url('/[subdomain]')
          grant.config.freshbooks.subdomain = 'request_url'
          oauth1.step1(grant.config.freshbooks, function (err, body) {
            body.oauth.should.match(/OAuth/)
            done()
          })
        })
      })

      after(function (done) {
        server.close(done)
      })
    })

    describe('step2', function () {
      before(function () {
        grant = new Grant(config)
      })

      describe('custom_params', function () {
        it('flickr', function () {
          grant.config.flickr.scope = ['read','write']
          var url = oauth1.step2(grant.config.flickr, {oauth_token:'token'})
          var query = qs.parse(url.split('?')[1])
          should.deepEqual(query,
            {oauth_token:'token', perms:['read','write']})
        })

        it('ravelry', function () {
          grant.config.ravelry.scope = ['read','write']
          var url = oauth1.step2(grant.config.ravelry, {oauth_token:'token'})
          var query = qs.parse(url.split('?')[1])
          should.deepEqual(query,
            {oauth_token:'token', scope:['read','write']})
        })

        it('trello', function () {
          grant.config.trello.custom_params = {expiration:'never', name:'Grant'}
          grant.config.trello.scope = ['read','write']
          var url = oauth1.step2(grant.config.trello, {oauth_token:'token'})
          var query = qs.parse(url.split('?')[1])
          should.deepEqual(query,
            {oauth_token:'token', scope:['read','write'], expiration:'never', name:'Grant'})
        })
      })

      describe('subdomain', function () {
        it('freshbooks', function () {
          grant.config.freshbooks.subdomain = 'grant'
          var url = oauth1.step2(grant.config.freshbooks, {oauth_token:'token'})
          url.indexOf('https://grant.freshbooks.com').should.equal(0)
        })
      })

      describe('oauth_callback', function () {
        it('tripit', function () {
          var uri = oauth1.step2(grant.config.tripit, {oauth_token:'token'})
          var query = qs.parse(uri.split('?')[1])
          should.deepEqual(query,
            {oauth_token:'token', oauth_callback:url('/connect/tripit/callback')})
        })
      })
    })

    describe('step3', function () {
      before(function (done) {
        grant = new Grant(config)
        app = express().use(grant)

        app.post('/access_url', function (req, res) {
          res.end(qs.stringify({oauth:req.headers.authorization}))
        })
        server = app.listen(5000, done)
      })

      describe('signature_method', function () {
        it('freshbooks', function (done) {
          grant.config.freshbooks.access_url = url('/access_url')
          oauth1.step3(grant.config.freshbooks, {}, {oauth_token:'token'}, function (err, response) {
            var query = qs.parse(response)
            query.raw.oauth.should.match(/oauth_signature_method="PLAINTEXT"/)
            done()
          })
        })
      })

      describe('oauth_verifier', function () {
        it('goodreads', function (done) {
          grant.config.goodreads.access_url = url('/access_url')
          oauth1.step3(grant.config.goodreads, {}, {oauth_token:'token'}, function (err, response) {
            var query = qs.parse(response)
            query.raw.oauth.should.not.match(/verifier/)
            done()
          })
        })
        it('tripit', function (done) {
          grant.config.tripit.access_url = url('/access_url')
          oauth1.step3(grant.config.tripit, {}, {oauth_token:'token'}, function (err, response) {
            var query = qs.parse(response)
            query.raw.oauth.should.not.match(/verifier/)
            done()
          })
        })
      })

      describe('subdomain', function () {
        it('freshbooks', function (done) {
          grant.config.freshbooks.access_url = url('/[subdomain]')
          grant.config.freshbooks.subdomain = 'access_url'
          oauth1.step3(grant.config.freshbooks, {}, {oauth_token:'token'}, function (err, url) {
            url.should.be.type('string')
            done()
          })
        })
      })

      after(function (done) {
        server.close(done)
      })
    })
  })
})
<|endoftext|>


<commit_before>import {LitElement, html} from "lit";
import LitUtils from "../commons/utils/lit-utils.js";
import NotificationUtils from "../commons/utils/notification-utils.js";

export default class UserPasswordReset extends LitElement {

    constructor() {
        super();
        this.#init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object
            },
        };
    }

    #init() {
        this.hasEmptyUser = false;
    }

    redirect(to) {
        LitUtils.dispatchCustomEvent(this, "redirect", null, {hash: to});
    }

    onSubmit(e) {
        e.preventDefault();
        const user = (this.querySelector("#user").value || "").trim();

        // Check for empty user ID
        this.hasEmptyUser = user.length === 0;
        if (this.hasEmptyUser) {
            return this.requestUpdate();
        }

        // Reset password mockup
        // TODO: call openCGA to the correct endpoint
        Promise.resolve().then(() => {
            // Reset user value
            this.querySelector("#user").value = "";
            NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_SUCCESS, {
                "message": "We have just send you an email with the new password.",
            });
        });
    }

    // Handle keyup event --> check for enter key to submit the form
    onKeyUp(e) {
        if (e.key === "Enter") {
            return this.onSubmit(e);
        }
    }

    render() {
        return html`

                                Reset your password

                            Please enter your user ID and we will send you an email with your password reset link.

                                <input id="user" type="text" class="form-control" placeholder="User ID" @keyup="${e => this.onKeyUp(e)}">

                            ${this.hasEmptyUser ? html`

This field is required

                            ` : null}

                        <button class="btn btn-primary btn-block" @click="${e => this.onSubmit(e)}">
                            Reset password
                        </button>

                     this.redirect("#login")}" style="cursor:pointer;">Cancel

        `;
    }

}

customElements.define("user-password-reset", UserPasswordReset);
<commit_msg>wc: minor improvements in password reset submit (#392)<commit_after>import {LitElement, html} from "lit";
import LitUtils from "../commons/utils/lit-utils.js";
import NotificationUtils from "../commons/utils/notification-utils.js";

export default class UserPasswordReset extends LitElement {

    constructor() {
        super();
        this.#init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object
            },
        };
    }

    #init() {
        this.hasEmptyUser = false;
    }

    redirect(to) {
        LitUtils.dispatchCustomEvent(this, "redirect", null, {hash: to});
    }

    onSubmit(e) {
        e.preventDefault();
        const user = (this.querySelector("#user").value || "").trim();

        // Check for empty user ID
        this.hasEmptyUser = user.length === 0;
        if (this.hasEmptyUser) {
            return this.requestUpdate();
        }

        // Reset password mockup
        // TODO: call openCGA to the correct endpoint
        Promise.resolve().then(() => {
            NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_SUCCESS, {
                "message": "We have just send you an email with the new password.",
            });

            this.querySelector("#user").value = "";
            this.hasEmptyUser = false;
            this.requestUpdate();
        });
    }

    // Handle keyup event --> check for enter key to submit the form
    onKeyUp(e) {
        if (e.key === "Enter") {
            return this.onSubmit(e);
        }
    }

    render() {
        return html`

                                Reset your password

                            Please enter your user ID and we will send you an email with your password reset link.

                                <input id="user" type="text" class="form-control" placeholder="User ID" @keyup="${e => this.onKeyUp(e)}">

                            ${this.hasEmptyUser ? html`

This field is required

                            ` : null}

                        <button class="btn btn-primary btn-block" @click="${e => this.onSubmit(e)}">
                            Reset password
                        </button>

                     this.redirect("#login")}" style="cursor:pointer;">Cancel

        `;
    }

}

customElements.define("user-password-reset", UserPasswordReset);
<|endoftext|>


<commit_before>app.controller('UserCtrl', function ($scope, $http, ModalService, authService, mediaService, toastr) {
  $scope.expand = false;
  $scope.searchResults = [];
  $scope.isSearching = false;
  $scope.isLoading = false;
  $scope.playlists={
    'Default':{
      Name:"Default", Active:true, Contents:[]
    }
  };
  $scope.playlistName="Default";
  $scope.inQueue=false;
  $scope.queue =[];
  $scope.isAdding = false;
  $scope.userData;
  fetch_playlist();

  function fetch_playlist(){
    if(!authService.getUser()){
      return;
    }
    $http.get('/api/playlists').then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.playlists = data.Playlists;
        for(pl in data.Playlists){
          if(pl.Active){
            $scope.playlistName = pl.Name;
            break;
          }
        }
      }
      else{
        toastr.error(data.Error, 'Problem retrieving playlist');
      }
    }, function(err){
      toastr.error(err, 'Problem retrieving playlist');
    });
  }

  function addToQueue(callback){
    if($scope.playlists[$scope.playlistName].Contents.length <1){
      $scope.isAdding = false;
      return;
    }
    if(checkPresence()){
      $scope.isAdding = false;
      return;
    }
    var vidinfo = $scope.playlists[$scope.playlistName].Contents.shift();
    if($scope.queue.indexOf(vidinfo) > -1){
      $scope.adding=false;
      $scope.playlists[$scope.playlistName].Contents.unshift(vidinfo);
      return;
    }
    $http.post('/api/radio/queue', vidinfo)
    .then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.playlists[$scope.playlistName].Contents.push(vidinfo);
        $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(){
          callback();
          $scope.isAdding = false;
        });
      }
      else{
        $scope.isAdding = false;
        callback(data.Error);
      }
    }, function(err){
      $scope.isAdding = false;
      callback(err);
    });
  };

  function checkPresence(){
    var present = false;
    var uname = authService.getUser().Username;
    $scope.queue.forEach(function(q_item){
      if(!q_item.DJ || q_item.DJ.toLowerCase() === uname.toLowerCase()){
        present = true;
      }
    });
    return present;
  }

  $scope.$on('queue_updated', function(event, queue){
    $scope.queue = queue;
    if(!$scope.inQueue || $scope.isAdding){
      return;
    }
    if(!checkPresence()){
      $scope.isAdding = true;
      addToQueue(function(err){
        return;
      });
    }
  });

  /*
  * Client Methods
  */
  $scope.search=function(){
    $scope.isSearching=true;
    $scope.isLoading = true;
    console.log('searching for ', $scope.searchCriteria.query);
    var cleancrit = encodeURIComponent($scope.searchCriteria.query)
    $http.get('/api/radio/search/'+cleancrit)
    .then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.searchResults = data.Videos;
      }
      $scope.isLoading = false;
    },function(error){
      $scope.isLoading = false;
      console.log(error);
    });
  }

  $scope.viewPlaylist=function(name){
    $scope.playlistName=name;
    $scope.isSearching = false;
  }

  $scope.addToPlaylist=function(vidinfo){
    if(!vidinfo){
      return;
    }
    if($scope.playlists[$scope.playlistName].Contents.indexOf(vidinfo) > -1){
      toastr.error('Song already exists in playlist');
      return;
    }
    toastr.success('Song Added to Playlist: ' + $scope.playlistName);
    $scope.playlists[$scope.playlistName].Contents.push(vidinfo);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      console.log('playlist updated');
    });
  }

  $scope.removeFromPlaylist=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents[ind];
    $scope.playlists[$scope.playlistName].Contents.splice(ind, 1);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){
      }
      else{
        console.log(data.Error);
      }
    });
  }

  $scope.moveUp=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents[ind];
    $scope.playlists[$scope.playlistName].Contents.splice(ind, 1);
    $scope.playlists[$scope.playlistName].Contents.unshift(item);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){

      }
      else{
        console.log(data.Error);
      }
    });
  }

  $scope.moveDown=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents[ind];
    $scope.playlists[$scope.playlistName].Contents.splice(ind, 1);
    $scope.playlists[$scope.playlistName].Contents.push(item);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){

      }
      else{
        console.log(data.Error);
      }
    });
  }

  $scope.joinLeaveQueue=function(){
    if($scope.inQueue){
      $scope.inQueue = false;
      return;
    }
    $scope.inQueue = true;
    addToQueue(function(err){});
  }

  $scope.login=function(){
    ModalService.showModal({
      templateUrl: "views/auth.html",
      controller: "AuthCtrl"
    }).then(function(modal) {
      modal.element.modal();
      modal.close.then(function(result) {
        fetch_playlist();
      });
    });
  };

  $scope.logOut=function(){
    authService.logOut();
  }

  $scope.getUser=function(){
    return authService.getUser();
  }

  $scope.$on('session_resume', function(){
    fetch_playlist();
  });

});
<commit_msg>add songs to the top of a playlist to avoid replaying old  songs first<commit_after>app.controller('UserCtrl', function ($scope, $http, ModalService, authService, mediaService, toastr) {
  $scope.expand = false;
  $scope.searchResults = [];
  $scope.isSearching = false;
  $scope.isLoading = false;
  $scope.playlists={
    'Default':{
      Name:"Default", Active:true, Contents:[]
    }
  };
  $scope.playlistName="Default";
  $scope.inQueue=false;
  $scope.queue =[];
  $scope.isAdding = false;
  $scope.userData;
  fetch_playlist();

  function fetch_playlist(){
    if(!authService.getUser()){
      return;
    }
    $http.get('/api/playlists').then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.playlists = data.Playlists;
        for(pl in data.Playlists){
          if(pl.Active){
            $scope.playlistName = pl.Name;
            break;
          }
        }
      }
      else{
        toastr.error(data.Error, 'Problem retrieving playlist');
      }
    }, function(err){
      toastr.error(err, 'Problem retrieving playlist');
    });
  }

  function addToQueue(callback){
    if($scope.playlists[$scope.playlistName].Contents.length <1){
      $scope.isAdding = false;
      return;
    }
    if(checkPresence()){
      $scope.isAdding = false;
      return;
    }
    var vidinfo = $scope.playlists[$scope.playlistName].Contents.shift();
    if($scope.queue.indexOf(vidinfo) > -1){
      $scope.adding=false;
      $scope.playlists[$scope.playlistName].Contents.unshift(vidinfo);
      return;
    }
    $http.post('/api/radio/queue', vidinfo)
    .then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.playlists[$scope.playlistName].Contents.push(vidinfo);
        $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(){
          callback();
          $scope.isAdding = false;
        });
      }
      else{
        $scope.isAdding = false;
        callback(data.Error);
      }
    }, function(err){
      $scope.isAdding = false;
      callback(err);
    });
  };

  function checkPresence(){
    var present = false;
    var uname = authService.getUser().Username;
    $scope.queue.forEach(function(q_item){
      if(!q_item.DJ || q_item.DJ.toLowerCase() === uname.toLowerCase()){
        present = true;
      }
    });
    return present;
  }

  $scope.$on('queue_updated', function(event, queue){
    $scope.queue = queue;
    if(!$scope.inQueue || $scope.isAdding){
      return;
    }
    if(!checkPresence()){
      $scope.isAdding = true;
      addToQueue(function(err){
        return;
      });
    }
  });

  /*
  * Client Methods
  */
  $scope.search=function(){
    $scope.isSearching=true;
    $scope.isLoading = true;
    console.log('searching for ', $scope.searchCriteria.query);
    var cleancrit = encodeURIComponent($scope.searchCriteria.query)
    $http.get('/api/radio/search/'+cleancrit)
    .then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.searchResults = data.Videos;
      }
      $scope.isLoading = false;
    },function(error){
      $scope.isLoading = false;
      console.log(error);
    });
  }

  $scope.viewPlaylist=function(name){
    $scope.playlistName=name;
    $scope.isSearching = false;
  }

  $scope.addToPlaylist=function(vidinfo){
    if(!vidinfo){
      return;
    }
    if($scope.playlists[$scope.playlistName].Contents.indexOf(vidinfo) > -1){
      toastr.error('Song already exists in playlist');
      return;
    }
    toastr.success('Song Added to Playlist: ' + $scope.playlistName);
    $scope.playlists[$scope.playlistName].Contents.unshift(vidinfo);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      console.log('playlist updated');
    });
  }

  $scope.removeFromPlaylist=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents[ind];
    $scope.playlists[$scope.playlistName].Contents.splice(ind, 1);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){
      }
      else{
        console.log(data.Error);
      }
    });
  }

  $scope.moveUp=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents[ind];
    $scope.playlists[$scope.playlistName].Contents.splice(ind, 1);
    $scope.playlists[$scope.playlistName].Contents.unshift(item);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){

      }
      else{
        console.log(data.Error);
      }
    });
  }

  $scope.moveDown=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents[ind];
    $scope.playlists[$scope.playlistName].Contents.splice(ind, 1);
    $scope.playlists[$scope.playlistName].Contents.push(item);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){

      }
      else{
        console.log(data.Error);
      }
    });
  }

  $scope.joinLeaveQueue=function(){
    if($scope.inQueue){
      $scope.inQueue = false;
      return;
    }
    $scope.inQueue = true;
    addToQueue(function(err){});
  }

  $scope.login=function(){
    ModalService.showModal({
      templateUrl: "views/auth.html",
      controller: "AuthCtrl"
    }).then(function(modal) {
      modal.element.modal();
      modal.close.then(function(result) {
        fetch_playlist();
      });
    });
  };

  $scope.logOut=function(){
    authService.logOut();
  }

  $scope.getUser=function(){
    return authService.getUser();
  }

  $scope.$on('session_resume', function(){
    fetch_playlist();
  });

});
<|endoftext|>


<commit_before>/* jshint strict: false, sub: true */
/* global print */
'use strict';

// //////////////////////////////////////////////////////////////////////////////
// / DISCLAIMER
// /
// / Copyright 2016 ArangoDB GmbH, Cologne, Germany
// / Copyright 2014 triagens GmbH, Cologne, Germany
// /
// / 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.
// /
// / Copyright holder is ArangoDB GmbH, Cologne, Germany
// /
// / @author Max Neunhoeffer
// //////////////////////////////////////////////////////////////////////////////

const functionsDocumentation = {
  'recovery': 'run recovery tests'
};
const optionsDocumentation = [
];

const fs = require('fs');
const pu = require('@arangodb/process-utils');
const tu = require('@arangodb/test-utils');
const _ = require('lodash');

const toArgv = require('internal').toArgv;

const RED = require('internal').COLORS.COLOR_RED;
const RESET = require('internal').COLORS.COLOR_RESET;
const BLUE = require('internal').COLORS.COLOR_BLUE;

const testPaths = {
  'recovery': [tu.pathForTesting('server/recovery')]
};

// //////////////////////////////////////////////////////////////////////////////
// / @brief TEST: recovery
// //////////////////////////////////////////////////////////////////////////////

function runArangodRecovery (params) {
  let useEncryption = false;

  if (global.ARANGODB_CLIENT_VERSION) {
    let version = global.ARANGODB_CLIENT_VERSION(true);
    if (version.hasOwnProperty('enterprise-version')) {
      useEncryption = true;
    }
  }

  let argv = [];

  let binary = pu.ARANGOD_BIN;

  if (params.setup) {
    params.options.disableMonitor = true;
    params.testDir = fs.join(params.tempDir, `${params.count}`);
    pu.cleanupDBDirectoriesAppend(params.testDir);
    let dataDir = fs.join(params.testDir, 'data');
    let appDir = fs.join(params.testDir, 'app');
    let tmpDir = fs.join(params.testDir, 'tmp');
    fs.makeDirectoryRecursive(params.testDir);
    fs.makeDirectoryRecursive(dataDir);
    fs.makeDirectoryRecursive(tmpDir);
    fs.makeDirectoryRecursive(appDir);

    let args = pu.makeArgs.arangod(params.options, appDir, '', tmpDir);
    // enable development debugging if extremeVerbosity is set
    if (params.options.extremeVerbosity === true) {
      args['log.level'] = 'development=info';
    }
    args = Object.assign(args, params.options.extraArgs);
    args = Object.assign(args, {
      'wal.reserve-logfiles': 1,
      'rocksdb.wal-file-timeout-initial': 10,
      'database.directory': fs.join(dataDir + 'db'),
      'server.rest-server': 'false',
      'replication.auto-start': 'true',
      'javascript.script': params.script
    });

    if (useEncryption) {
      const key = '01234567890123456789012345678901';
      let keyDir = fs.join(fs.getTempPath(), 'arango_encryption');
      if (!fs.exists(keyDir)) {  // needed on win32
        fs.makeDirectory(keyDir);
      }
      pu.cleanupDBDirectoriesAppend(keyDir);

      let keyfile = fs.join(keyDir, 'rocksdb-encryption-keyfile');
      fs.write(keyfile, key);

      args['rocksdb.encryption-keyfile'] = keyfile;
      process.env["rocksdb-encryption-keyfile"] = keyfile;
    }

    params.args = args;

    argv = toArgv(
      Object.assign(params.args,
                    {
                      'log.foreground-tty': 'true',
                      'javascript.script-parameter': 'setup'
                    }
                   )
    );
  } else {
    argv = toArgv(
      Object.assign(params.args,
                    {
                      'log.foreground-tty': 'true',
                      'wal.ignore-logfile-errors': 'true',
                      'database.ignore-datafile-errors': 'false', // intentionally false!
                      'javascript.script-parameter': 'recovery'
                    }
                   )
    );
    if (params.options.rr) {
      binary = 'rr';
      argv.unshift(pu.ARANGOD_BIN);
    }
  }
  params.instanceInfo.pid = pu.executeAndWait(
    binary,
    argv,
    params.options,
    'recovery',
    params.instanceInfo.rootDir,
    !params.setup && params.options.coreCheck);
}

function recovery (options) {
  if (!global.ARANGODB_CLIENT_VERSION(true)['failure-tests'] ||
      global.ARANGODB_CLIENT_VERSION(true)['failure-tests'] === 'false') {
    return {
      recovery: {
        status: false,
        message: 'failure-tests not enabled. please recompile with -DUSE_FAILURE_TESTS=On'
      },
      status: false
    };
  }

  let results = {
    status: true
  };

  let recoveryTests = tu.scanTestPaths(testPaths.recovery, options);

  recoveryTests = tu.splitBuckets(options, recoveryTests);

  let count = 0;
  let orgTmp = process.env.TMPDIR;
  let tempDir = fs.join(fs.getTempPath(), 'recovery');
  fs.makeDirectoryRecursive(tempDir);
  process.env.TMPDIR = tempDir;
  pu.cleanupDBDirectoriesAppend(tempDir);

  for (let i = 0; i < recoveryTests.length; ++i) {
    let test = recoveryTests[i];
    let filtered = {};

    if (tu.filterTestcaseByOptions(test, options, filtered)) {
      count += 1;
      ////////////////////////////////////////////////////////////////////////
      print(BLUE + "running setup of test " + count + " - " + test + RESET);
      let params = {
        tempDir: tempDir,
        instanceInfo: {
          rootDir: fs.join(fs.getTempPath(), 'recovery', count.toString())
        },
        options: _.cloneDeep(options),
        script: test,
        setup: true,
        count: count,
        testDir: ""
      };
      runArangodRecovery(params);

      ////////////////////////////////////////////////////////////////////////
      print(BLUE + "running recovery of test " + count + " - " + test + RESET);
      params.options.disableMonitor = options.disableMonitor;
      params.setup = false;
      try {
        tu.writeTestResult(params.args['temp.path'], {
          failed: 1,
          status: false,
          message: "unable to run recovery test " + test,
          duration: -1
        });
      } catch (er) {}
      runArangodRecovery(params);

      results[test] = tu.readTestResult(
        params.args['temp.path'],
        {
          status: false
        },
        test
      );
      if (!results[test].status) {
        print("Not cleaning up " + params.testDir);
        results.status = false;
      }
      else {
        pu.cleanupLastDirectory(params.options);
      }
    } else {
      if (options.extremeVerbosity) {
        print('Skipped ' + test + ' because of ' + filtered.filter);
      }
    }
  }
  process.env.TMPDIR = orgTmp;
  if (count === 0) {
    print(RED + 'No testcase matched the filter.' + RESET);
    return {
      ALLTESTS: {
        status: true,
        skipped: true
      },
      status: true
    };
  }

  return results;
}

exports.setup = function (testFns, defaultFns, opts, fnDocs, optionsDoc, allTestPaths) {
  Object.assign(allTestPaths, testPaths);
  testFns['recovery'] = recovery;
  for (var attrname in functionsDocumentation) { fnDocs[attrname] = functionsDocumentation[attrname]; }
  for (var i = 0; i < optionsDocumentation.length; i++) { optionsDoc.push(optionsDocumentation[i]); }
};
<commit_msg>remove obsolete options from recovery test (#11654)<commit_after>/* jshint strict: false, sub: true */
/* global print */
'use strict';

// //////////////////////////////////////////////////////////////////////////////
// / DISCLAIMER
// /
// / Copyright 2016 ArangoDB GmbH, Cologne, Germany
// / Copyright 2014 triagens GmbH, Cologne, Germany
// /
// / 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.
// /
// / Copyright holder is ArangoDB GmbH, Cologne, Germany
// /
// / @author Max Neunhoeffer
// //////////////////////////////////////////////////////////////////////////////

const functionsDocumentation = {
  'recovery': 'run recovery tests'
};
const optionsDocumentation = [
];

const fs = require('fs');
const pu = require('@arangodb/process-utils');
const tu = require('@arangodb/test-utils');
const _ = require('lodash');

const toArgv = require('internal').toArgv;

const RED = require('internal').COLORS.COLOR_RED;
const RESET = require('internal').COLORS.COLOR_RESET;
const BLUE = require('internal').COLORS.COLOR_BLUE;

const testPaths = {
  'recovery': [tu.pathForTesting('server/recovery')]
};

// //////////////////////////////////////////////////////////////////////////////
// / @brief TEST: recovery
// //////////////////////////////////////////////////////////////////////////////

function runArangodRecovery (params) {
  let useEncryption = false;

  if (global.ARANGODB_CLIENT_VERSION) {
    let version = global.ARANGODB_CLIENT_VERSION(true);
    if (version.hasOwnProperty('enterprise-version')) {
      useEncryption = true;
    }
  }

  let argv = [];

  let binary = pu.ARANGOD_BIN;

  if (params.setup) {
    params.options.disableMonitor = true;
    params.testDir = fs.join(params.tempDir, `${params.count}`);
    pu.cleanupDBDirectoriesAppend(params.testDir);
    let dataDir = fs.join(params.testDir, 'data');
    let appDir = fs.join(params.testDir, 'app');
    let tmpDir = fs.join(params.testDir, 'tmp');
    fs.makeDirectoryRecursive(params.testDir);
    fs.makeDirectoryRecursive(dataDir);
    fs.makeDirectoryRecursive(tmpDir);
    fs.makeDirectoryRecursive(appDir);

    let args = pu.makeArgs.arangod(params.options, appDir, '', tmpDir);
    // enable development debugging if extremeVerbosity is set
    if (params.options.extremeVerbosity === true) {
      args['log.level'] = 'development=info';
    }
    args = Object.assign(args, params.options.extraArgs);
    args = Object.assign(args, {
      'rocksdb.wal-file-timeout-initial': 10,
      'database.directory': fs.join(dataDir + 'db'),
      'server.rest-server': 'false',
      'replication.auto-start': 'true',
      'javascript.script': params.script
    });

    if (useEncryption) {
      const key = '01234567890123456789012345678901';
      let keyDir = fs.join(fs.getTempPath(), 'arango_encryption');
      if (!fs.exists(keyDir)) {  // needed on win32
        fs.makeDirectory(keyDir);
      }
      pu.cleanupDBDirectoriesAppend(keyDir);

      let keyfile = fs.join(keyDir, 'rocksdb-encryption-keyfile');
      fs.write(keyfile, key);

      args['rocksdb.encryption-keyfile'] = keyfile;
      process.env["rocksdb-encryption-keyfile"] = keyfile;
    }

    params.args = args;

    argv = toArgv(
      Object.assign(params.args,
                    {
                      'log.foreground-tty': 'true',
                      'javascript.script-parameter': 'setup'
                    }
                   )
    );
  } else {
    argv = toArgv(
      Object.assign(params.args,
                    {
                      'log.foreground-tty': 'true',
                      'database.ignore-datafile-errors': 'false', // intentionally false!
                      'javascript.script-parameter': 'recovery'
                    }
                   )
    );
    if (params.options.rr) {
      binary = 'rr';
      argv.unshift(pu.ARANGOD_BIN);
    }
  }
  params.instanceInfo.pid = pu.executeAndWait(
    binary,
    argv,
    params.options,
    'recovery',
    params.instanceInfo.rootDir,
    !params.setup && params.options.coreCheck);
}

function recovery (options) {
  if (!global.ARANGODB_CLIENT_VERSION(true)['failure-tests'] ||
      global.ARANGODB_CLIENT_VERSION(true)['failure-tests'] === 'false') {
    return {
      recovery: {
        status: false,
        message: 'failure-tests not enabled. please recompile with -DUSE_FAILURE_TESTS=On'
      },
      status: false
    };
  }

  let results = {
    status: true
  };

  let recoveryTests = tu.scanTestPaths(testPaths.recovery, options);

  recoveryTests = tu.splitBuckets(options, recoveryTests);

  let count = 0;
  let orgTmp = process.env.TMPDIR;
  let tempDir = fs.join(fs.getTempPath(), 'recovery');
  fs.makeDirectoryRecursive(tempDir);
  process.env.TMPDIR = tempDir;
  pu.cleanupDBDirectoriesAppend(tempDir);

  for (let i = 0; i < recoveryTests.length; ++i) {
    let test = recoveryTests[i];
    let filtered = {};

    if (tu.filterTestcaseByOptions(test, options, filtered)) {
      count += 1;
      ////////////////////////////////////////////////////////////////////////
      print(BLUE + "running setup of test " + count + " - " + test + RESET);
      let params = {
        tempDir: tempDir,
        instanceInfo: {
          rootDir: fs.join(fs.getTempPath(), 'recovery', count.toString())
        },
        options: _.cloneDeep(options),
        script: test,
        setup: true,
        count: count,
        testDir: ""
      };
      runArangodRecovery(params);

      ////////////////////////////////////////////////////////////////////////
      print(BLUE + "running recovery of test " + count + " - " + test + RESET);
      params.options.disableMonitor = options.disableMonitor;
      params.setup = false;
      try {
        tu.writeTestResult(params.args['temp.path'], {
          failed: 1,
          status: false,
          message: "unable to run recovery test " + test,
          duration: -1
        });
      } catch (er) {}
      runArangodRecovery(params);

      results[test] = tu.readTestResult(
        params.args['temp.path'],
        {
          status: false
        },
        test
      );
      if (!results[test].status) {
        print("Not cleaning up " + params.testDir);
        results.status = false;
      }
      else {
        pu.cleanupLastDirectory(params.options);
      }
    } else {
      if (options.extremeVerbosity) {
        print('Skipped ' + test + ' because of ' + filtered.filter);
      }
    }
  }
  process.env.TMPDIR = orgTmp;
  if (count === 0) {
    print(RED + 'No testcase matched the filter.' + RESET);
    return {
      ALLTESTS: {
        status: true,
        skipped: true
      },
      status: true
    };
  }

  return results;
}

exports.setup = function (testFns, defaultFns, opts, fnDocs, optionsDoc, allTestPaths) {
  Object.assign(allTestPaths, testPaths);
  testFns['recovery'] = recovery;
  for (var attrname in functionsDocumentation) { fnDocs[attrname] = functionsDocumentation[attrname]; }
  for (var i = 0; i < optionsDocumentation.length; i++) { optionsDoc.push(optionsDocumentation[i]); }
};
<|endoftext|>


<commit_before>// import axios from 'axios'
import {ipcMain as ipc, dialog} from 'electron'
import {focusOrNewSecondaryWindow, focusMainWindow} from './windows'
import {getSubMenuFromMenu, disableSubMenuItemsFromMenuObject, enableSubMenuItemsFromMenuObject} from './menu.js'
import {Package} from 'datapackage'

export function showUrlDialog() {
  let labels = ['Zip File...', 'URL...']
  let menu = getSubMenuFromMenu('File', 'Open Data Package')
  disableSubMenuItemsFromMenuObject(menu, labels)
  let browserWindow = focusOrNewSecondaryWindow('urldialog', {width: 300, height: 150, modal: true, alwaysOnTop: true})
  browserWindow.on('closed', function () {
    enableSubMenuItemsFromMenuObject(menu, labels)
  })
  browserWindow.webContents.on('did-finish-load', function() {
    ipc.once('urlCancelled', function() {
      if (browserWindow) {
        browserWindow.close()
      }
    })
    ipc.once('urlSubmitted', function(e, urlText) {
      console.log(`text is ${urlText}`)
      if (browserWindow) {
        browserWindow.close()
      }
      const mainWindow = focusMainWindow()
      loadPackageJson(urlText, mainWindow)
      // mainWindow.webContents.send('importDataPackageJsonUrl', urlText)
    })
  })
}

// datapackage-js does not support loading url in browser
async function loadPackageJson(json, mainWindow) {
  try {
    const dataPackage = await Package.load(json)
    console.log(dataPackage)
  } catch (error) {
    // console.log(`There was a problem loading the package: ${json}`, error)
    dialog.showMessageBox(mainWindow, {
      type: 'warning',
      // title is not displayed on screen on macOS
      title: `Unable to load Data Package`,
      message:
`The data package, ${json}, could not be loaded.
If the data package is a URL, please check that the URL exists.`
    })
  }
  return dataPackage
}
<commit_msg>#284: corrected return placement.<commit_after>// import axios from 'axios'
import {ipcMain as ipc, dialog} from 'electron'
import {focusOrNewSecondaryWindow, focusMainWindow} from './windows'
import {getSubMenuFromMenu, disableSubMenuItemsFromMenuObject, enableSubMenuItemsFromMenuObject} from './menu.js'
import {Package} from 'datapackage'

export function showUrlDialog() {
  let labels = ['Zip File...', 'URL...']
  let menu = getSubMenuFromMenu('File', 'Open Data Package')
  disableSubMenuItemsFromMenuObject(menu, labels)
  let browserWindow = focusOrNewSecondaryWindow('urldialog', {width: 300, height: 150, modal: true, alwaysOnTop: true})
  browserWindow.on('closed', function () {
    enableSubMenuItemsFromMenuObject(menu, labels)
  })
  browserWindow.webContents.on('did-finish-load', function() {
    ipc.once('urlCancelled', function() {
      if (browserWindow) {
        browserWindow.close()
      }
    })
    ipc.once('urlSubmitted', function(e, urlText) {
      console.log(`text is ${urlText}`)
      if (browserWindow) {
        browserWindow.close()
      }
      const mainWindow = focusMainWindow()
      loadPackageJson(urlText, mainWindow)
      // mainWindow.webContents.send('importDataPackageJsonUrl', urlText)
    })
  })
}

// datapackage-js does not support loading url in browser
async function loadPackageJson(json, mainWindow) {
  try {
    const dataPackage = await Package.load(json)
    console.log(dataPackage)
    return dataPackage
  } catch (error) {
    // console.log(`There was a problem loading the package: ${json}`, error)
    dialog.showMessageBox(mainWindow, {
      type: 'warning',
      // title is not displayed on screen on macOS
      title: `Unable to load Data Package`,
      message:
`The data package, ${json}, could not be loaded.
If the data package is a URL, please check that the URL exists.`
    })
  }
}
<|endoftext|>


<commit_before>const EventEmitter = require("events");

if (!document) {
    throw Error("electron-tabs module must be called in renderer process");
}

// Inject styles
(function () {
    const styles = `
        webview {
            display: flex;
            flex: 0 1;
            width: 0px;
            height: 0px;
        }
        webview.visible {
            width: 100%;
            height: 100%;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
        }
    `;
    let styleTag = document.createElement("style");
    styleTag.innerHTML = styles;
    document.getElementsByTagName("head")[0].appendChild(styleTag);
})();

class TabGroup extends EventEmitter {
    constructor (args = {}) {
        super();
        let options = this.options = {
            tabContainerSelector: args.tabContainerSelector || ".tabs-tabcontainer",
            buttonsContainerSelector: args.buttonsContainerSelector || ".tabs-buttonscontainer",
            viewContainerSelector: args.viewContainerSelector || ".tabs-viewcontainer",
            tabClass: args.tabClass || "tabs-tab",
            viewClass: args.viewClass || "tabs-view",
            closeButtonText: args.closeButtonText || "❌",
            newTab: args.newTab,
            newTabButtonText: args.newTabButton || "+",
            ready: args.ready
        };
        this.tabContainer = document.querySelector(options.tabContainerSelector);
        this.viewContainer = document.querySelector(options.viewContainerSelector);
        this.tabs = [];
        this.newTabId = 0;
        TabGroupPrivate.initNewTabButton.bind(this)();
        if (typeof this.options.ready === "function") {
            this.options.ready(this);
        }
    }

    addTab (args = this.options.newTab) {
        if (typeof args === "function") {
            args = args(this);
        }
        let id = this.newTabId;
        this.newTabId++;
        let tab = new Tab(this, id, args);
        this.tabs.push(tab);
        this.emit("tab-added", tab, this);
        return tab;
    }

    getTab (id) {
        for (let i in this.tabs) {
            if (this.tabs[i].id === id) {
                return this.tabs[i];
            }
        }
        return null;
    }

    getActiveTab () {
        if (this.tabs.length === 0) return null;
        return this.tabs[0];
    }
}

const TabGroupPrivate = {
    initNewTabButton: function () {
        if (!this.options.newTab) return;
        let container = document.querySelector(this.options.buttonsContainerSelector);
        let button = container.appendChild(document.createElement("button"));
        button.classList.add(`${this.options.tabClass}-button-new`);
        button.innerHTML = this.options.newTabButtonText;
        button.addEventListener("click", this.addTab.bind(this, undefined), false);
    },

    removeTab: function (tab, triggerEvent) {
        let id = tab.id;
        for (let i in this.tabs) {
            if (this.tabs[i].id === id) {
                this.tabs.splice(i, 1);
                break;
            }
        }
        if (triggerEvent) {
            this.emit("tab-removed", tab, this);
        }
        return this;
    },

    setActiveTab: function (tab) {
        TabGroupPrivate.removeTab.bind(this)(tab);
        this.tabs.unshift(tab);
        this.emit("tab-active", tab, this);
        return this;
    },

    activateRecentTab: function (tab) {
        if (this.tabs.length > 0) {
            this.tabs[0].activate();
        }
        return this;
    }
};

class Tab extends EventEmitter {
    constructor (tabGroup, id, args) {
        super();
        this.tabGroup = tabGroup;
        this.id = id;
        this.title = args.title;
        this.iconURL = args.iconURL;
        this.closable = args.closable === false ? false : true;
        this.webviewAttributes = args.webviewAttributes || {};
        this.webviewAttributes.src = args.src;
        this.tabElements = {};
        TabPrivate.initTab.bind(this)();
        TabPrivate.initWebview.bind(this)();
        if (args.visible) {
            this.show();
        }
        if (typeof args.ready === "function") {
            args.ready(this);
        }
    }

    setTitle (title) {
        if (this.isClosed) return;
        let span = this.tabElements.title;
        span.innerHTML = title;
        this.title = title;
        this.emit("title-changed", title, this);
        return this;
    }

    getTitle () {
        if (this.isClosed) return;
        return this.title;
    }

    setIcon (iconURL) {
        if (this.isClosed) return;
        this.iconURL = iconURL;
        let span = this.tabElements.icon;
        if (iconURL) {
            span.innerHTML = `<img src="${iconURL}" />`;
        }
        this.emit("icon-changed", iconURL, this);
        return this;
    }

    getIcon () {
        if (this.isClosed) return;
        return this.iconURL;
    }

    activate () {
        if (this.isClosed) return;
        let activeTab = this.tabGroup.getActiveTab();
        if (activeTab) {
            activeTab.tab.classList.remove("active");
            activeTab.webview.classList.remove("visible");
        }
        TabGroupPrivate.setActiveTab.bind(this.tabGroup)(this);
        this.tab.classList.add("active");
        this.webview.classList.add("visible");
        this.emit("active", this);
        return this;
    }

    show () {
        if (this.isClosed) return;
        this.tab.classList.add("visible");
        return this;
    }

    hide () {
        if (this.isClosed) return;
        this.tab.classList.remove("visible");
        return this;
    }

    flash (flag) {
        if (this.isClosed) return;
        if (flag !== false) {
            this.tab.classList.add("flash");
            this.emit("flash-start", this);
        } else {
            this.tab.classList.remove("flash");
            this.emit("flash-end", this);
        }
        return this;
    }

    close (force) {
        if (this.isClosed || (!this.closable && !force)) return;
        this.isClosed = true;
        let tabGroup = this.tabGroup;
        tabGroup.tabContainer.removeChild(this.tab);
        tabGroup.viewContainer.removeChild(this.webview);
        TabGroupPrivate.removeTab.bind(tabGroup)(this, true);
        this.emit("close", this);
        TabGroupPrivate.activateRecentTab.bind(tabGroup)();
    }
}

const TabPrivate = {
    initTab: function () {
        let tabClass = this.tabGroup.options.tabClass;

        // Create tab element
        let tab = this.tab = document.createElement("div");
        tab.classList.add(tabClass);
        for (let el of ["icon", "title", "buttons"]) {
            let span = tab.appendChild(document.createElement("span"));
            span.classList.add(`${tabClass}-${el}`);
            this.tabElements[el] = span;
        }

        this.setTitle(this.title);
        this.setIcon(this.iconURL);
        TabPrivate.initTabButtons.bind(this)();
        TabPrivate.initTabClickHandler.bind(this)();

        this.tabGroup.tabContainer.appendChild(this.tab);
    },

    initTabButtons: function () {
        let container = this.tabElements.buttons;
        let tabClass = this.tabGroup.options.tabClass;
        if (this.closable) {
            let button = container.appendChild(document.createElement("button"));
            button.classList.add(`${tabClass}-button-close`);
            button.innerHTML = this.tabGroup.options.closeButtonText;
            button.addEventListener("click", this.close.bind(this), false);
        }
    },

    initTabClickHandler: function () {
        const tabClickHandler = function (e) {
            if (this.isClosed) return;
            if (e.which === 1) {
                this.activate();
            } else if (e.which === 2) {
                this.close();
            }
        };
        this.tab.addEventListener("click", tabClickHandler.bind(this), false);
    },

    initWebview: function () {
        this.webview = document.createElement("webview");
        this.webview.classList.add(this.tabGroup.options.viewClass);
        if (this.webviewAttributes) {
            let attrs = this.webviewAttributes;
            for (let key in attrs) {
                this.webview.setAttribute(key, attrs[key]);
            }
        }
        this.tabGroup.viewContainer.appendChild(this.webview);
    }
};

module.exports = TabGroup;
<commit_msg>Make consistant API for flash and show<commit_after>const EventEmitter = require("events");

if (!document) {
    throw Error("electron-tabs module must be called in renderer process");
}

// Inject styles
(function () {
    const styles = `
        webview {
            display: flex;
            flex: 0 1;
            width: 0px;
            height: 0px;
        }
        webview.visible {
            width: 100%;
            height: 100%;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
        }
    `;
    let styleTag = document.createElement("style");
    styleTag.innerHTML = styles;
    document.getElementsByTagName("head")[0].appendChild(styleTag);
})();

class TabGroup extends EventEmitter {
    constructor (args = {}) {
        super();
        let options = this.options = {
            tabContainerSelector: args.tabContainerSelector || ".tabs-tabcontainer",
            buttonsContainerSelector: args.buttonsContainerSelector || ".tabs-buttonscontainer",
            viewContainerSelector: args.viewContainerSelector || ".tabs-viewcontainer",
            tabClass: args.tabClass || "tabs-tab",
            viewClass: args.viewClass || "tabs-view",
            closeButtonText: args.closeButtonText || "❌",
            newTab: args.newTab,
            newTabButtonText: args.newTabButton || "+",
            ready: args.ready
        };
        this.tabContainer = document.querySelector(options.tabContainerSelector);
        this.viewContainer = document.querySelector(options.viewContainerSelector);
        this.tabs = [];
        this.newTabId = 0;
        TabGroupPrivate.initNewTabButton.bind(this)();
        if (typeof this.options.ready === "function") {
            this.options.ready(this);
        }
    }

    addTab (args = this.options.newTab) {
        if (typeof args === "function") {
            args = args(this);
        }
        let id = this.newTabId;
        this.newTabId++;
        let tab = new Tab(this, id, args);
        this.tabs.push(tab);
        this.emit("tab-added", tab, this);
        return tab;
    }

    getTab (id) {
        for (let i in this.tabs) {
            if (this.tabs[i].id === id) {
                return this.tabs[i];
            }
        }
        return null;
    }

    getActiveTab () {
        if (this.tabs.length === 0) return null;
        return this.tabs[0];
    }
}

const TabGroupPrivate = {
    initNewTabButton: function () {
        if (!this.options.newTab) return;
        let container = document.querySelector(this.options.buttonsContainerSelector);
        let button = container.appendChild(document.createElement("button"));
        button.classList.add(`${this.options.tabClass}-button-new`);
        button.innerHTML = this.options.newTabButtonText;
        button.addEventListener("click", this.addTab.bind(this, undefined), false);
    },

    removeTab: function (tab, triggerEvent) {
        let id = tab.id;
        for (let i in this.tabs) {
            if (this.tabs[i].id === id) {
                this.tabs.splice(i, 1);
                break;
            }
        }
        if (triggerEvent) {
            this.emit("tab-removed", tab, this);
        }
        return this;
    },

    setActiveTab: function (tab) {
        TabGroupPrivate.removeTab.bind(this)(tab);
        this.tabs.unshift(tab);
        this.emit("tab-active", tab, this);
        return this;
    },

    activateRecentTab: function (tab) {
        if (this.tabs.length > 0) {
            this.tabs[0].activate();
        }
        return this;
    }
};

class Tab extends EventEmitter {
    constructor (tabGroup, id, args) {
        super();
        this.tabGroup = tabGroup;
        this.id = id;
        this.title = args.title;
        this.iconURL = args.iconURL;
        this.closable = args.closable === false ? false : true;
        this.webviewAttributes = args.webviewAttributes || {};
        this.webviewAttributes.src = args.src;
        this.tabElements = {};
        TabPrivate.initTab.bind(this)();
        TabPrivate.initWebview.bind(this)();
        if (args.visible) {
            this.show();
        }
        if (typeof args.ready === "function") {
            args.ready(this);
        }
    }

    setTitle (title) {
        if (this.isClosed) return;
        let span = this.tabElements.title;
        span.innerHTML = title;
        this.title = title;
        this.emit("title-changed", title, this);
        return this;
    }

    getTitle () {
        if (this.isClosed) return;
        return this.title;
    }

    setIcon (iconURL) {
        if (this.isClosed) return;
        this.iconURL = iconURL;
        let span = this.tabElements.icon;
        if (iconURL) {
            span.innerHTML = `<img src="${iconURL}" />`;
        }
        this.emit("icon-changed", iconURL, this);
        return this;
    }

    getIcon () {
        if (this.isClosed) return;
        return this.iconURL;
    }

    activate () {
        if (this.isClosed) return;
        let activeTab = this.tabGroup.getActiveTab();
        if (activeTab) {
            activeTab.tab.classList.remove("active");
            activeTab.webview.classList.remove("visible");
        }
        TabGroupPrivate.setActiveTab.bind(this.tabGroup)(this);
        this.tab.classList.add("active");
        this.webview.classList.add("visible");
        this.emit("active", this);
        return this;
    }

    show (flag) {
        if (this.isClosed) return;
        if (flag !== false) {
            this.tab.classList.add("visible");
            this.emit("visible", this);
        } else {
            this.tab.classList.remove("visible");
            this.emit("hidden", this);
        }
        return this;
    }

    hide () {
        return this.show(false);
    }

    flash (flag) {
        if (this.isClosed) return;
        if (flag !== false) {
            this.tab.classList.add("flash");
            this.emit("flash", this);
        } else {
            this.tab.classList.remove("flash");
            this.emit("unflash", this);
        }
        return this;
    }

    unflash () {
        return this.flash(false);
    }

    close (force) {
        if (this.isClosed || (!this.closable && !force)) return;
        this.isClosed = true;
        let tabGroup = this.tabGroup;
        tabGroup.tabContainer.removeChild(this.tab);
        tabGroup.viewContainer.removeChild(this.webview);
        TabGroupPrivate.removeTab.bind(tabGroup)(this, true);
        this.emit("close", this);
        TabGroupPrivate.activateRecentTab.bind(tabGroup)();
    }
}

const TabPrivate = {
    initTab: function () {
        let tabClass = this.tabGroup.options.tabClass;

        // Create tab element
        let tab = this.tab = document.createElement("div");
        tab.classList.add(tabClass);
        for (let el of ["icon", "title", "buttons"]) {
            let span = tab.appendChild(document.createElement("span"));
            span.classList.add(`${tabClass}-${el}`);
            this.tabElements[el] = span;
        }

        this.setTitle(this.title);
        this.setIcon(this.iconURL);
        TabPrivate.initTabButtons.bind(this)();
        TabPrivate.initTabClickHandler.bind(this)();

        this.tabGroup.tabContainer.appendChild(this.tab);
    },

    initTabButtons: function () {
        let container = this.tabElements.buttons;
        let tabClass = this.tabGroup.options.tabClass;
        if (this.closable) {
            let button = container.appendChild(document.createElement("button"));
            button.classList.add(`${tabClass}-button-close`);
            button.innerHTML = this.tabGroup.options.closeButtonText;
            button.addEventListener("click", this.close.bind(this), false);
        }
    },

    initTabClickHandler: function () {
        const tabClickHandler = function (e) {
            if (this.isClosed) return;
            if (e.which === 1) {
                this.activate();
            } else if (e.which === 2) {
                this.close();
            }
        };
        this.tab.addEventListener("click", tabClickHandler.bind(this), false);
    },

    initWebview: function () {
        this.webview = document.createElement("webview");
        this.webview.classList.add(this.tabGroup.options.viewClass);
        if (this.webviewAttributes) {
            let attrs = this.webviewAttributes;
            for (let key in attrs) {
                this.webview.setAttribute(key, attrs[key]);
            }
        }
        this.tabGroup.viewContainer.appendChild(this.webview);
    }
};

module.exports = TabGroup;
<|endoftext|>


<commit_before>/* eslint-disable no-console */
/* eslint-disable react/prop-types */
/* eslint-disable react/destructuring-assignment */
import React from 'react';
import { View, Text } from 'react-native';

export const ObjectField = props => {
  console.log('-------------------------------------------');
  console.log('ObjectField - props', props);
  console.log('-------------------------------------------');
  return (
    <View style={{ marginLeft: 10, borderWidth: 1 }}>
      <Text>ObjectFieldTemplate</Text>
      {props.properties.map(element => element.content)}
    </View>
  );
};
<commit_msg>Add update to ObjectField template, removing the border<commit_after>export const ObjectField = props => {
  const { properties } = props;
  return properties.map(element => element.content);
};
<|endoftext|>


<commit_before>module.exports = EmbeddedPlayground;

var _ = require('lodash');
var http = require('http');
var mercury = require('mercury');
var moment = require('moment');
var path = require('path');
var url = require('url');

var Editor = require('./editor');

var m = mercury;
var h = mercury.h;

// Shows each file in a tab.
// * el: The DOM element to mount on.
// * id: Identifier for this playground instance, used in debug messages.
// * files: List of {name, body}, as written by bundler.
function EmbeddedPlayground(el, id, files) {
  this.id_ = id;
  this.files_ = _.map(files, function(file) {
    return _.assign({}, file, {
      basename: path.basename(file.name),
      type: path.extname(file.name).substr(1)
    });
  });
  this.editors_ = _.map(this.files_, function(file) {
    return new Editor(file.type, file.body);
  });
  this.state_ = m.struct({
    activeTab: m.value(0),
    nextRunId: m.value(0),
    running: m.value(false),
    hasRun: m.value(false),
    consoleEvents: m.value([])
  });
  mercury.app(el, this.state_, this.render_.bind(this));
}

EmbeddedPlayground.prototype.renderTopBar_ = function(state) {
  var that = this;

  var tabs = _.map(this.files_, function(file, i) {
    var selector = 'div.tab';
    if (i === state.activeTab) {
      selector += '.active';
    }
    return h(selector, {
      'ev-click': function() {
        that.state_.activeTab.set(i);
      }
    }, file.basename);
  });

  var runBtn = h('button.btn', {
    'ev-click': that.run.bind(that)
  }, 'Run');
  var resetBtn = h('button.btn', {
    'ev-click': that.reset.bind(that)
  }, 'Reset');

  return h('div.top-bar', [h('div', tabs), h('div.btns', [runBtn, resetBtn])]);
};

EmbeddedPlayground.prototype.renderEditors_ = function(state) {
  var editors = _.map(this.editors_, function(editor, i) {
    var properties = {};
    if (i !== state.activeTab) {
      // Use "visibility: hidden" rather than "display: none" because the latter
      // causes the editor to initialize lazily and thus flicker when it's first
      // opened.
      properties['style'] = {visibility: 'hidden'};
    }
    return h('div.editor', properties, editor);
  });

  return h('div.editors', editors);
};

function renderConsoleEvent(event) {
  var children = [];
  if (event.Timestamp) {
    // Convert UTC to local time.
    var t = moment(event.Timestamp / 1e6);
    children.push(h('span.timestamp', t.format('H:mm:ss.SSS') + ' '));
  }
  if (event.File) {
    children.push(h('span.filename', path.basename(event.File) + ': '));
  }
  children.push(h('span.' + (event.Stream || 'unknown'), event.Message));
  return h('div', children);
}

EmbeddedPlayground.prototype.renderConsole_ = function(state) {
  if (state.hasRun) {
    return h('div.console.open', [
      h('div.text', _.map(state.consoleEvents, renderConsoleEvent))
    ]);
  }
  return h('div.console');
};

EmbeddedPlayground.prototype.render_ = function(state) {
  return h('div.pg', [
    this.renderTopBar_(state),
    this.renderEditors_(state),
    this.renderConsole_(state)
  ]);
};

// Sends the files to the backend, then injects the response in the console.
EmbeddedPlayground.prototype.run = function() {
  if (this.state_.running()) {
    console.log('Already running', this.id_);
    return;
  }
  var runId = this.state_.nextRunId();

  // TODO(sadovsky): Visually disable the "Run" button or change it to a "Stop"
  // button.
  this.state_.running.set(true);
  this.state_.hasRun.set(true);
  this.state_.consoleEvents.set([{Message: 'Running...'}]);

  var myUrl = url.parse(window.location.href, true);
  var pgaddr = myUrl.query.pgaddr;
  if (pgaddr) {
    console.log('Using pgaddr', pgaddr);
  } else {
    pgaddr = 'https://staging.v.io/playground';
  }
  var compileUrl = pgaddr + '/compile';
  if (myUrl.query.debug === '1') {
    compileUrl += '?debug=1';
  }

  var editors = this.editors_;
  var reqData = {
    files: _.map(this.files_, function(file, i) {
      var editor = editors[i];
      return {
        Name: file.name,
        Body: editor.getText()
      };
    }),
    Identities: []
  };

  // TODO(sadovsky): To deal with cached responses, shift timestamps (based on
  // current time) and introduce a fake delay. Also, switch to streaming
  // messages, for usability.
  var that = this, state = this.state_;

  // If the user has stopped this run or reset the playground, returns false.
  var isRunActive = function() {
    return runId === state.nextRunId();
  };
  var appendToConsole = function(events) {
    state.consoleEvents.set(state.consoleEvents().concat(events));
  };
  var makeEvent = function(stream, message) {
    return {Stream: stream, Message: message};
  };

  var optp = url.parse(compileUrl);

  var options = {
    method: 'POST',
    protocol: optp.protocol,
    hostname: optp.hostname,
    port: optp.port || (optp.protocol === 'https:' ? '443' : '80'),
    path: optp.path,
    // TODO(ivanpi): Change once deployed.
    withCredentials: false,
    headers: {
      'accept': 'application/json',
      'content-type': 'application/json'
    }
  };

  var req = http.request(options);

  var endRunIfActive = function() {
    if (isRunActive()) {
      that.endRun_();
    }
  };

  req.on('error', function(err) {
    if (isRunActive()) {
      console.log(err);
      appendToConsole(makeEvent('syserr', 'Error connecting to server.'));
      process.nextTick(endRunIfActive);
    }
  });

  req.on('response', function(res) {
    if (isRunActive()) {
      if (res.statusCode !== 0 && res.statusCode !== 200) {
        appendToConsole(makeEvent('syserr', 'HTTP status ' + res.statusCode));
      }
      // Holds partial prefix of next line.
      var line = { buffer: '' };
      res.on('data', function(chunk) {
        if (isRunActive()) {
          // Each complete line is one JSON Event.
          var eventsJson = (line.buffer + chunk).split('\n');
          line.buffer = eventsJson.pop();
          var events = [];
          _.forEach(eventsJson, function(el) {
            // Ignore empty and invalid lines.
            if (el && el.charAt(0) === '{') {
              try {
                events.push(JSON.parse(el));
              } catch (err) {
                console.error(err);
                events.push(makeEvent('syserr',
                    'Error parsing server response.'));
                endRunIfActive();
                return false;
              }
            }
          });
          appendToConsole(events);
        }
      });
    }
  });

  req.on('close', function() {
    if (isRunActive()) {
      process.nextTick(endRunIfActive);
    }
  });

  req.write(JSON.stringify(reqData));

  req.end();
};

// Clears the console and resets all editors to their original contents.
EmbeddedPlayground.prototype.reset = function() {
  this.state_.consoleEvents.set([]);
  _.forEach(this.editors_, function(editor) {
    editor.reset();
  });
  this.endRun_();
  this.state_.hasRun.set(false);
};

EmbeddedPlayground.prototype.endRun_ = function() {
  this.state_.nextRunId.set(this.state_.nextRunId() + 1);
  this.state_.running.set(false);
};
<commit_msg>playground: Enable realtime streaming of playground output.<commit_after>module.exports = EmbeddedPlayground;

var _ = require('lodash');
var http = require('http');
var mercury = require('mercury');
var moment = require('moment');
var path = require('path');
var url = require('url');

var Editor = require('./editor');

var m = mercury;
var h = mercury.h;

// Shows each file in a tab.
// * el: The DOM element to mount on.
// * id: Identifier for this playground instance, used in debug messages.
// * files: List of {name, body}, as written by bundler.
function EmbeddedPlayground(el, id, files) {
  this.id_ = id;
  this.files_ = _.map(files, function(file) {
    return _.assign({}, file, {
      basename: path.basename(file.name),
      type: path.extname(file.name).substr(1)
    });
  });
  this.editors_ = _.map(this.files_, function(file) {
    return new Editor(file.type, file.body);
  });
  this.state_ = m.struct({
    activeTab: m.value(0),
    nextRunId: m.value(0),
    running: m.value(false),
    hasRun: m.value(false),
    consoleEvents: m.value([])
  });
  mercury.app(el, this.state_, this.render_.bind(this));
}

EmbeddedPlayground.prototype.renderTopBar_ = function(state) {
  var that = this;

  var tabs = _.map(this.files_, function(file, i) {
    var selector = 'div.tab';
    if (i === state.activeTab) {
      selector += '.active';
    }
    return h(selector, {
      'ev-click': function() {
        that.state_.activeTab.set(i);
      }
    }, file.basename);
  });

  var runBtn = h('button.btn', {
    'ev-click': that.run.bind(that)
  }, 'Run');
  var resetBtn = h('button.btn', {
    'ev-click': that.reset.bind(that)
  }, 'Reset');

  return h('div.top-bar', [h('div', tabs), h('div.btns', [runBtn, resetBtn])]);
};

EmbeddedPlayground.prototype.renderEditors_ = function(state) {
  var editors = _.map(this.editors_, function(editor, i) {
    var properties = {};
    if (i !== state.activeTab) {
      // Use "visibility: hidden" rather than "display: none" because the latter
      // causes the editor to initialize lazily and thus flicker when it's first
      // opened.
      properties['style'] = {visibility: 'hidden'};
    }
    return h('div.editor', properties, editor);
  });

  return h('div.editors', editors);
};

function renderConsoleEvent(event) {
  var children = [];
  if (event.Timestamp) {
    // Convert UTC to local time.
    var t = moment(event.Timestamp / 1e6);
    children.push(h('span.timestamp', t.format('H:mm:ss.SSS') + ' '));
  }
  if (event.File) {
    children.push(h('span.filename', path.basename(event.File) + ': '));
  }
  children.push(h('span.' + (event.Stream || 'unknown'), event.Message));
  return h('div', children);
}

EmbeddedPlayground.prototype.renderConsole_ = function(state) {
  if (state.hasRun) {
    return h('div.console.open', [
      h('div.text', _.map(state.consoleEvents, renderConsoleEvent))
    ]);
  }
  return h('div.console');
};

EmbeddedPlayground.prototype.render_ = function(state) {
  return h('div.pg', [
    this.renderTopBar_(state),
    this.renderEditors_(state),
    this.renderConsole_(state)
  ]);
};

// Sends the files to the backend, then injects the response in the console.
EmbeddedPlayground.prototype.run = function() {
  if (this.state_.running()) {
    console.log('Already running', this.id_);
    return;
  }
  var runId = this.state_.nextRunId();

  // TODO(sadovsky): Visually disable the "Run" button or change it to a "Stop"
  // button.
  this.state_.running.set(true);
  this.state_.hasRun.set(true);
  this.state_.consoleEvents.set([{Message: 'Running...'}]);

  var myUrl = url.parse(window.location.href, true);
  var pgaddr = myUrl.query.pgaddr;
  if (pgaddr) {
    console.log('Using pgaddr', pgaddr);
  } else {
    pgaddr = 'https://staging.v.io/playground';
  }
  var compileUrl = pgaddr + '/compile';
  if (myUrl.query.debug === '1') {
    compileUrl += '?debug=1';
  }

  var editors = this.editors_;
  var reqData = {
    files: _.map(this.files_, function(file, i) {
      var editor = editors[i];
      return {
        Name: file.name,
        Body: editor.getText()
      };
    }),
    Identities: []
  };

  // TODO(sadovsky): To deal with cached responses, shift timestamps (based on
  // current time) and introduce a fake delay. Also, switch to streaming
  // messages, for usability.
  var that = this, state = this.state_;

  // If the user stops the current run or resets the playground, functions
  // wrapped with ifRunActive become no-ops.
  var ifRunActive = function(foo) {
    return function() {
      if (runId === state.nextRunId()) {
        foo.apply(this, arguments);
      }
    };
  };

  var appendToConsole = function(events) {
    state.consoleEvents.set(state.consoleEvents().concat(events));
  };
  var makeEvent = function(stream, message) {
    return {Stream: stream, Message: message};
  };
  var endRunIfActive = ifRunActive(function() {
    that.endRun_();
  });

  var optp = url.parse(compileUrl);

  var options = {
    method: 'POST',
    protocol: optp.protocol,
    hostname: optp.hostname,
    port: optp.port || (optp.protocol === 'https:' ? '443' : '80'),
    path: optp.path,
    // TODO(ivanpi): Change once deployed.
    withCredentials: false,
    headers: {
      'accept': 'application/json',
      'content-type': 'application/json'
    }
  };

  var req = http.request(options);

  // error and close callbacks call endRunIfActive in the next tick to ensure
  // that if both events are triggered, both are executed before the run is
  // ended by one of them.
  req.on('error', ifRunActive(function(err) {
    console.log(err);
    appendToConsole(makeEvent('syserr', 'Error connecting to server.'));
    process.nextTick(endRunIfActive);
  }));

  req.on('close', ifRunActive(function() {
    process.nextTick(endRunIfActive);
  }));

  req.on('response', ifRunActive(function(res) {
    if (res.statusCode !== 0 && res.statusCode !== 200) {
      appendToConsole(makeEvent('syserr', 'HTTP status ' + res.statusCode));
    }
    // Holds partial prefix of next line.
    var line = {buffer: ''};
    res.on('data', ifRunActive(function(chunk) {
      // Each complete line is one JSON Event.
      var eventsJson = (line.buffer + chunk).split('\n');
      line.buffer = eventsJson.pop();
      var events = [];
      _.forEach(eventsJson, function(el) {
        // Ignore empty and invalid lines.
        if (el && el.charAt(0) === '{') {
          try {
            events.push(JSON.parse(el));
          } catch (err) {
            console.error(err);
            events.push(makeEvent('syserr', 'Error parsing server response.'));
            endRunIfActive();
            return false;
          }
        }
      });
      appendToConsole(events);
    }));
  }));

  req.write(JSON.stringify(reqData));
  req.end();
};

// Clears the console and resets all editors to their original contents.
EmbeddedPlayground.prototype.reset = function() {
  this.state_.consoleEvents.set([]);
  _.forEach(this.editors_, function(editor) {
    editor.reset();
  });
  this.endRun_();
  this.state_.hasRun.set(false);
};

EmbeddedPlayground.prototype.endRun_ = function() {
  this.state_.nextRunId.set(this.state_.nextRunId() + 1);
  this.state_.running.set(false);
};
<|endoftext|>


<commit_before>var express = require('express');

  var app = express();

  var spawn = require('child_process').spawn;

  app.get('/garage-door/:action', function(req, res) {
    var action = req.params.action;
    const ls = spawn('/opt/pi_garage_trigger.py', [action]);

    ls.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`);
      res.json({response: `output: ${data}`})
    });

    ls.stderr.on('data', (data) => {
      console.log(`stderr: ${data}`);
    });

    ls.on('close', (code) => {
      console.log(`invoked script exited with code ${code}`);
    });
  })

  app.listen(8888);
<commit_msg>Delete index.js<commit_after><|endoftext|>


<commit_before>var junk = require('junk');
var q = require('q');

var Manifest = function(config, md5, glob, fs) {
    this.config = config;
    this.md5 = md5;
    this.glob = glob;
    this.fs = fs;
};

var filterJunk = function(files) {
    return files.filter(junk.not);
};

var originalManifestList;

/**
 * Retrieve the file list from the manifest file.
 *
 * @return promise
 */
Manifest.prototype.fileList = function() {
    // Subsequent calls shouldn't need to get the list again.
    if (originalManifestList) {
        return q(originalManifestList);
    }
    return q.nfcall(this.fs.readFile, process.cwd() + '/bitbin.manifest.json', {encoding: 'utf8'})
        .then(function(files) {
            files = JSON.parse(files);
            // Cache the original list
            return originalManifestList = files;
        })
        .catch(function() {
            // @todo should check the err here to see if file doesn't exist or general error.
            return [];
        });
};

/**
 * Retrieve all files located in the configured paths.
 *
 * @return promise
 */
Manifest.prototype.localFiles = function() {
    var pathPromises = [];
    var glob = this.glob;
    this.config.retrieve().paths.forEach(function(path) {
        pathPromises.push(q.nfcall(glob, path, {nodir: true}).then(filterJunk));
    });
    return !pathPromises.length ?
        q.fcall(function() {
            throw new Error('No paths defined.');
        }) :
        q.all(pathPromises)
            // flatten all the path files down to one array of files.
            .then(function(fileGroups) {
                return fileGroups.reduce(function(a, b) {
                    return a.concat(b);
                });
            });
};

/**
 * Compute MD5 hashes for all files and transposes the data into array of objects.
 *
 * @param array files
 * @return promise
 */
Manifest.prototype.transposeWithMD5 = function(files) {
    var sumPromises = [];
    var md5 = this.md5;
    var cwd = process.cwd();
    files.forEach(function(file) {
        sumPromises.push(md5.computeFromFile(cwd + '/' + file));
    });
    return q.all(sumPromises)
        // map the sums
        .then(function(data) {
            var entries = [];
            files.forEach(function(entry, i) {
                entries.push({
                    name: entry,
                    hash: data[i]
                });
            });
            return entries;
        });
};

/**
 * Filter the provided files based on files already in the manifest.
 *
 * @param Array files
 * @return promise
 */
Manifest.prototype.filterInManifest = function(files) {
    return this.fileList()
        .then(function(manifestFiles) {
            return files.filter(function(file) {
                return !manifestFiles.some(function(entry) {
                    return entry.name === file.name && entry.hash === file.hash;
                });
            });
        })
        .then(function(filteredFiles) {
            var err;
            if (!filteredFiles.length) {
                err = new Error('All contents match the manifest.');
                err.derail = true;
                throw err;
            }
            return filteredFiles;
        })
        .catch(function(err) {
            if (!err.derail) {
                return files;
            }
            throw err;
        });
};

module.exports = Manifest;
module.exports.$name = 'manifest';
module.exports.$inject = ['config', 'md5', 'glob', 'node.fs'];
<commit_msg>Added a manifest update mechanism.<commit_after>var junk = require('junk');
var q = require('q');

var Manifest = function(config, md5, glob, fs) {
    this.config = config;
    this.md5 = md5;
    this.glob = glob;
    this.fs = fs;
};

var filterJunk = function(files) {
    return files.filter(junk.not);
};

var originalManifestList;

/**
 * Retrieve the file list from the manifest file.
 *
 * @return promise
 */
Manifest.prototype.fileList = function() {
    // Subsequent calls shouldn't need to get the list again.
    if (originalManifestList) {
        return q(originalManifestList);
    }
    return q.nfcall(this.fs.readFile, process.cwd() + '/bitbin.manifest.json', {encoding: 'utf8'})
        .then(function(files) {
            files = JSON.parse(files);
            // Cache the original list
            return originalManifestList = files;
        })
        .catch(function() {
            // @todo should check the err here to see if file doesn't exist or general error.
            return [];
        });
};

/**
 * Retrieve all files located in the configured paths.
 *
 * @return promise
 */
Manifest.prototype.localFiles = function() {
    var pathPromises = [];
    var glob = this.glob;
    this.config.retrieve().paths.forEach(function(path) {
        pathPromises.push(q.nfcall(glob, path, {nodir: true}).then(filterJunk));
    });
    return !pathPromises.length ?
        q.fcall(function() {
            throw new Error('No paths defined.');
        }) :
        q.all(pathPromises)
            // flatten all the path files down to one array of files.
            .then(function(fileGroups) {
                return fileGroups.reduce(function(a, b) {
                    return a.concat(b);
                });
            });
};

/**
 * Compute MD5 hashes for all files and transposes the data into array of objects.
 *
 * @param array files
 * @return promise
 */
Manifest.prototype.transposeWithMD5 = function(files) {
    var sumPromises = [];
    var md5 = this.md5;
    var cwd = process.cwd();
    files.forEach(function(file) {
        sumPromises.push(md5.computeFromFile(cwd + '/' + file));
    });
    return q.all(sumPromises)
        // map the sums
        .then(function(data) {
            var entries = [];
            files.forEach(function(entry, i) {
                entries.push({
                    name: entry,
                    hash: data[i]
                });
            });
            return entries;
        });
};

/**
 * Filter the provided files based on files already in the manifest.
 *
 * @param Array files
 * @return promise
 */
Manifest.prototype.filterInManifest = function(files) {
    return this.fileList()
        .then(function(manifestFiles) {
            return files.filter(function(file) {
                return !manifestFiles.some(function(entry) {
                    return entry.name === file.name && entry.hash === file.hash;
                });
            });
        })
        .then(function(filteredFiles) {
            var err;
            if (!filteredFiles.length) {
                err = new Error('All contents match the manifest.');
                err.derail = true;
                throw err;
            }
            return filteredFiles;
        })
        .catch(function(err) {
            if (!err.derail) {
                return files;
            }
            throw err;
        });
};

/**
 * Update manifest for files that have been updated.
 *
 * @param array files
 * @return array
 */
Manifest.prototype.update = function(files) {
    var fs = this.fs;
    return this.fileList()
        .then(function(manifestFiles) {
            var hash = {};
            manifestFiles.forEach(function(file, i) {
                hash[file.name] = [i, file];
            });
            files.forEach(function(file) {
                var entry = {
                    name: file.name,
                    hash: file.hash
                };
                if (hash.hasOwnProperty(file.originalName)) {
                    manifestFiles[hash[file.originalName][0]] = entry;
                } else {
                    manifestFiles.push(entry);
                }
            });
            return manifestFiles;
        })
        .then(function(manifestFiles) {
            return q.nfcall(
                fs.writeFile,
                process.cwd() + '/bitbin.manifest.json',
                JSON.stringify(manifestFiles, null, 4)
            ).then(function() {
                return files;
            });
        });
};

module.exports = Manifest;
module.exports.$name = 'manifest';
module.exports.$inject = ['config', 'md5', 'glob', 'node.fs'];
<|endoftext|>