From 378db7ffe417e93ec78c11a88b72cc29bcfb0ce9 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Fri, 7 Jul 2017 15:54:52 -0700 Subject: [PATCH] adds a method to import a tweet on demand --- app/Events/NewTweetEvent.php | 2 + app/Http/Controllers/DashboardController.php | 3 +- app/Http/Controllers/ImportController.php | 116 + public/css/app.css | 4 +- public/js/app.js | 20816 ++++++++-------- resources/assets/js/app.js | 1 + .../assets/js/components/ImportTweet.vue | 99 + resources/assets/js/components/Mission1.vue | 0 resources/assets/sass/app.scss | 24 +- resources/views/import.blade.php | 5 + resources/views/team-tweets.blade.php | 2 +- routes/web.php | 5 + 12 files changed, 10766 insertions(+), 10311 deletions(-) create mode 100644 app/Http/Controllers/ImportController.php create mode 100644 resources/assets/js/components/ImportTweet.vue delete mode 100644 resources/assets/js/components/Mission1.vue create mode 100644 resources/views/import.blade.php diff --git a/app/Events/NewTweetEvent.php b/app/Events/NewTweetEvent.php index 5104976..eec2adc 100644 --- a/app/Events/NewTweetEvent.php +++ b/app/Events/NewTweetEvent.php @@ -26,6 +26,7 @@ class NewTweetEvent implements ShouldBroadcast public $photos; public $mission; public $mission_id; + public $twitter_id; /** * Create a new event instance. @@ -44,6 +45,7 @@ class NewTweetEvent implements ShouldBroadcast $this->photos = json_decode($tweet->photo); $this->mission = ($tweet->mission ? $tweet->mission->hashtag : null); $this->mission_id = $tweet->mission_id; + $this->twitter_id = $tweet->tweet_id; } /** diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 3093049..f1b59eb 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -27,8 +27,7 @@ class DashboardController extends Controller */ public function index() { - return view('dashboard', [ - ]); + return view('dashboard', []); } public function queue() { diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php new file mode 100644 index 0000000..e7f9f36 --- /dev/null +++ b/app/Http/Controllers/ImportController.php @@ -0,0 +1,116 @@ +middleware('auth'); + } + + public function index(Request $request) { + return view('import', []); + } + + public function preview(Request $request) { + $url = $request->input('url'); + if(preg_match('/twitter\.com\/.+\/status(?:es)?\/(\d+)/', $url, $match)) { + $tweetID = $match[1]; + } else { + return response()->json(['error'=>'Invalid URL']); + } + + try { + $data = Twitter::getTweet($tweetID); + } catch(\Exception $e) { + return response()->json(['error'=>'Could not fetch tweet']); + } + + $player = Player::where('twitter_user_id', $data->user->id_str)->first(); + + if(!$player) { + return response()->json(['error'=>'Couldn\'t find the player for this tweet. Check that they are added to a team.']); + } + + $tweet = self::buildTweetFromTwitterObject($player, $data); + $event = new NewTweetEvent($tweet); + + unset($event->socket); + + return response()->json($event); + } + + public function save(Request $request) { + $tweetID = $request->input('tweet_id'); + + try { + $data = Twitter::getTweet($tweetID); + } catch(\Exception $e) { + return response()->json(['error'=>'Could not fetch tweet']); + } + + $player = Player::where('twitter_user_id', $data->user->id_str)->first(); + + if(!$player) { + return response()->json(['error'=>'Couldn\'t find the player for this tweet. Check that they are added to a team.']); + } + + $tweet = self::buildTweetFromTwitterObject($player, $data); + $tweet->save(); + + if($tweet->mission_id && $tweet->team_id) { + event(new NewTweetEvent($tweet)); + } + + return response()->json(['result'=>'ok']); + } + + private static function buildTweetFromTwitterObject($player, $data) { + + if(isset($data->extended_tweet->full_text)) + $text = $data->extended_tweet->full_text; + else + $text = $data->text; + + // Unshorten URLs + if(isset($data->entities->urls)) { + foreach($data->entities->urls as $url) { + $text = str_replace($url->url, $url->expanded_url, $text); + } + } + + // Remove media URLs from tweet text + $photos = []; + if(isset($data->extended_entities->media)) { + foreach($data->extended_entities->media as $media) { + $text = str_replace($media->url, '', $text); + $photos[] = $media->media_url_https; + } + $text = trim($text); + } + + $mission_id = 0; + foreach(Mission::all() as $mission) { + if(strpos($text, $mission->hashtag) !== false) { + $mission_id = $mission->id; + } + } + + $tweet = new Tweet; + $tweet->tweet_id = $data->id_str; + $tweet->player_id = $player ? $player->id : 0; + $tweet->team_id = $player ? $player->team->id : 0; + $tweet->text = $text; + $tweet->photo = json_encode($photos, JSON_UNESCAPED_SLASHES); + $tweet->mission_id = $mission_id; + $tweet->tweet_date = date('Y-m-d H:i:s', strtotime($data->created_at)); + return $tweet; + } + +} diff --git a/public/css/app.css b/public/css/app.css index 3a55613..8243326 100644 --- a/public/css/app.css +++ b/public/css/app.css @@ -8762,14 +8762,14 @@ button.close { margin-right: 4px; } -.tweet { +.tweet-list .tweet { border: 1px #d3e0e9 solid; border-radius: 4px; padding: 6px; margin-bottom: 6px; } -.tweet .text { +.tweet-list .tweet .text { white-space: pre-wrap; font-size: 1.5em; margin: 8px 0; diff --git a/public/js/app.js b/public/js/app.js index a533186..7de3a72 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -870,14 +870,13 @@ module.exports = function normalizeComponent ( /***/ (function(module, exports, __webpack_require__) { __webpack_require__(10); -module.exports = __webpack_require__(45); +module.exports = __webpack_require__(47); /***/ }), /* 10 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/***/ (function(module, exports, __webpack_require__) { -"use strict"; /** * First we will load all of this project's JavaScript dependencies which @@ -893,7 +892,7 @@ $.ajaxSetup({ } }); -window.Vue = __webpack_require__(38); +window.Vue = __webpack_require__(40); /** * Next, we will create a fresh Vue application instance and attach it to @@ -901,8 +900,9 @@ window.Vue = __webpack_require__(38); * or customize the JavaScript scaffolding to fit your unique needs. */ -Vue.component('tweet-queue', __webpack_require__(56)); -Vue.component('scorecard', __webpack_require__(59)); +Vue.component('tweet-queue', __webpack_require__(41)); +Vue.component('import-tweet', __webpack_require__(57)); +Vue.component('scorecard', __webpack_require__(44)); var data = { queue: [], @@ -920,7 +920,7 @@ var app = new Vue({ "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_laravel_echo__ = __webpack_require__(36); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_laravel_echo__ = __webpack_require__(37); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_laravel_echo___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_laravel_echo__); window._ = __webpack_require__(12); @@ -947,7 +947,7 @@ window.axios = __webpack_require__(16); window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; -__webpack_require__(64); +__webpack_require__(36); $.featherlight.autoBind = false; /** @@ -972,7 +972,7 @@ if (token) { -window.Pusher = __webpack_require__(37); +window.Pusher = __webpack_require__(38); window.Echo = new __WEBPACK_IMPORTED_MODULE_0_laravel_echo___default.a({ broadcaster: 'pusher', @@ -981,7 +981,7 @@ window.Echo = new __WEBPACK_IMPORTED_MODULE_0_laravel_echo___default.a({ encrypted: true }); -window.twitter = __webpack_require__(65); +window.twitter = __webpack_require__(39); /***/ }), /* 12 */ @@ -31814,6 +31814,19 @@ module.exports = function spread(callback) { /* 36 */ /***/ (function(module, exports) { +/** + * Featherlight - ultra slim jQuery lightbox + * Version 1.7.6 - http://noelboss.github.io/featherlight/ + * + * Copyright 2017, Noël Raoul Bossart (http://www.noelboss.com) + * MIT Licensed. +**/ +!function(a){"use strict";function b(a,c){if(!(this instanceof b)){var d=new b(a,c);return d.open(),d}this.id=b.id++,this.setup(a,c),this.chainCallbacks(b._callbackChain)}function c(a,b){var c={};for(var d in a)d in b&&(c[d]=a[d],delete a[d]);return c}function d(a,b){var c={},d=new RegExp("^"+b+"([A-Z])(.*)");for(var e in a){var f=e.match(d);if(f){var g=(f[1]+f[2].replace(/([A-Z])/g,"-$1")).toLowerCase();c[g]=a[e]}}return c}if("undefined"==typeof a)return void("console"in window&&window.console.info("Too much lightness, Featherlight needs jQuery."));var e=[],f=function(b){return e=a.grep(e,function(a){return a!==b&&a.$instance.closest("body").length>0})},g={allowfullscreen:1,frameborder:1,height:1,longdesc:1,marginheight:1,marginwidth:1,name:1,referrerpolicy:1,scrolling:1,sandbox:1,src:1,srcdoc:1,width:1},h={keyup:"onKeyUp",resize:"onResize"},i=function(c){a.each(b.opened().reverse(),function(){return c.isDefaultPrevented()||!1!==this[h[c.type]](c)?void 0:(c.preventDefault(),c.stopPropagation(),!1)})},j=function(c){if(c!==b._globalHandlerInstalled){b._globalHandlerInstalled=c;var d=a.map(h,function(a,c){return c+"."+b.prototype.namespace}).join(" ");a(window)[c?"on":"off"](d,i)}};b.prototype={constructor:b,namespace:"featherlight",targetAttr:"data-featherlight",variant:null,resetCss:!1,background:null,openTrigger:"click",closeTrigger:"click",filter:null,root:"body",openSpeed:250,closeSpeed:250,closeOnClick:"background",closeOnEsc:!0,closeIcon:"✕",loading:"",persist:!1,otherClose:null,beforeOpen:a.noop,beforeContent:a.noop,beforeClose:a.noop,afterOpen:a.noop,afterContent:a.noop,afterClose:a.noop,onKeyUp:a.noop,onResize:a.noop,type:null,contentFilters:["jquery","image","html","ajax","iframe","text"],setup:function(b,c){"object"!=typeof b||b instanceof a!=!1||c||(c=b,b=void 0);var d=a.extend(this,c,{target:b}),e=d.resetCss?d.namespace+"-reset":d.namespace,f=a(d.background||['
','
','",'
'+d.loading+"
","
","
"].join("")),g="."+d.namespace+"-close"+(d.otherClose?","+d.otherClose:"");return d.$instance=f.clone().addClass(d.variant),d.$instance.on(d.closeTrigger+"."+d.namespace,function(b){var c=a(b.target);("background"===d.closeOnClick&&c.is("."+d.namespace)||"anywhere"===d.closeOnClick||c.closest(g).length)&&(d.close(b),b.preventDefault())}),this},getContent:function(){if(this.persist!==!1&&this.$content)return this.$content;var b=this,c=this.constructor.contentFilters,d=function(a){return b.$currentTarget&&b.$currentTarget.attr(a)},e=d(b.targetAttr),f=b.target||e||"",g=c[b.type];if(!g&&f in c&&(g=c[f],f=b.target&&e),f=f||d("href")||"",!g)for(var h in c)b[h]&&(g=c[h],f=b[h]);if(!g){var i=f;if(f=null,a.each(b.contentFilters,function(){return g=c[this],g.test&&(f=g.test(i)),!f&&g.regex&&i.match&&i.match(g.regex)&&(f=i),!f}),!f)return"console"in window&&window.console.error("Featherlight: no content filter found "+(i?' for "'+i+'"':" (no target specified)")),!1}return g.process.call(b,f)},setContent:function(b){var c=this;return b.is("iframe")&&c.$instance.addClass(c.namespace+"-iframe"),c.$instance.removeClass(c.namespace+"-loading"),c.$instance.find("."+c.namespace+"-inner").not(b).slice(1).remove().end().replaceWith(a.contains(c.$instance[0],b[0])?"":b),c.$content=b.addClass(c.namespace+"-inner"),c},open:function(b){var c=this;if(c.$instance.hide().appendTo(c.root),!(b&&b.isDefaultPrevented()||c.beforeOpen(b)===!1)){b&&b.preventDefault();var d=c.getContent();if(d)return e.push(c),j(!0),c.$instance.fadeIn(c.openSpeed),c.beforeContent(b),a.when(d).always(function(a){c.setContent(a),c.afterContent(b)}).then(c.$instance.promise()).done(function(){c.afterOpen(b)})}return c.$instance.detach(),a.Deferred().reject().promise()},close:function(b){var c=this,d=a.Deferred();return c.beforeClose(b)===!1?d.reject():(0===f(c).length&&j(!1),c.$instance.fadeOut(c.closeSpeed,function(){c.$instance.detach(),c.afterClose(b),d.resolve()})),d.promise()},resize:function(a,b){if(a&&b){this.$content.css("width","").css("height","");var c=Math.max(a/(parseInt(this.$content.parent().css("width"),10)-1),b/(parseInt(this.$content.parent().css("height"),10)-1));c>1&&(c=b/Math.floor(b/c),this.$content.css("width",""+a/c+"px").css("height",""+b/c+"px"))}},chainCallbacks:function(b){for(var c in b)this[c]=a.proxy(b[c],this,a.proxy(this[c],this))}},a.extend(b,{id:0,autoBind:"[data-featherlight]",defaults:b.prototype,contentFilters:{jquery:{regex:/^[#.]\w/,test:function(b){return b instanceof a&&b},process:function(b){return this.persist!==!1?a(b):a(b).clone(!0)}},image:{regex:/\.(png|jpg|jpeg|gif|tiff|bmp|svg)(\?\S*)?$/i,process:function(b){var c=this,d=a.Deferred(),e=new Image,f=a('');return e.onload=function(){f.naturalWidth=e.width,f.naturalHeight=e.height,d.resolve(f)},e.onerror=function(){d.reject(f)},e.src=b,d.promise()}},html:{regex:/^\s*<[\w!][^<]*>/,process:function(b){return a(b)}},ajax:{regex:/./,process:function(b){var c=a.Deferred(),d=a("
").load(b,function(a,b){"error"!==b&&c.resolve(d.contents()),c.fail()});return c.promise()}},iframe:{process:function(b){var e=new a.Deferred,f=a("