From cbb0b306d45d724669e7890a70caa29eaab76cad Mon Sep 17 00:00:00 2001 From: Jeff Reifman Date: Mon, 9 Mar 2015 12:44:05 -0700 Subject: [PATCH] Interim check in for twitter --- controllers/MomentController.php | 23 ++++ controllers/TwitterController.php | 121 ++++++++++++++++++ .../m150309_174014_create_twitter_table.php | 35 +++++ models/Moment.php | 83 +++++++++++- models/Twitter.php | 101 +++++++++++++++ models/TwitterSearch.php | 74 +++++++++++ views/moment/browse_twitter.php | 51 ++++++++ views/moment/index.php | 5 +- views/twitter/_form.php | 39 ++++++ views/twitter/_search.php | 45 +++++++ views/twitter/create.php | 21 +++ views/twitter/index.php | 43 +++++++ views/twitter/update.php | 21 +++ views/twitter/view.php | 44 +++++++ 14 files changed, 704 insertions(+), 2 deletions(-) create mode 100644 controllers/TwitterController.php create mode 100644 migrations/m150309_174014_create_twitter_table.php create mode 100644 models/Twitter.php create mode 100644 models/TwitterSearch.php create mode 100644 views/moment/browse_twitter.php create mode 100644 views/twitter/_form.php create mode 100644 views/twitter/_search.php create mode 100644 views/twitter/create.php create mode 100644 views/twitter/index.php create mode 100644 views/twitter/update.php create mode 100644 views/twitter/view.php diff --git a/controllers/MomentController.php b/controllers/MomentController.php index 6b81f14..406a3a1 100644 --- a/controllers/MomentController.php +++ b/controllers/MomentController.php @@ -6,6 +6,7 @@ use app\models\Moment; use app\models\MomentSearch; use app\models\Gram; +use app\models\Twitter; use yii\web\Controller; use yii\web\NotFoundHttpException; use yii\filters\VerbFilter; @@ -67,6 +68,20 @@ public function actionBrowse($id) 'moment_id'=>$id, ]); } + + public function actionBrowse_twitter($id) + { + // browse twitter results for moment $id + $dataProvider = new ActiveDataProvider([ + 'query' => Twitter::find()->where(['moment_id'=>$id])->orderBy('tweeted_at ASC') + ]); + + return $this->render('browse_twitter', [ + 'dataProvider' => $dataProvider, + 'moment_id'=>$id, + ]); + } + public function actionPurge($id) { Moment::purge($id); @@ -80,6 +95,14 @@ public function actionInstagram($id) $model->searchInstagram(); return $this->redirect(['browse', 'id' => $model->id]); } + + public function actionTwitter($id) + { + $model = $this->findModel($id); + $model->searchTwitter(); + return $this->redirect(['browse_twitter', 'id' => $model->id]); + } + /** * Creates a new Moment model. * If creation is successful, the browser will be redirected to the 'view' page. diff --git a/controllers/TwitterController.php b/controllers/TwitterController.php new file mode 100644 index 0000000..92ad572 --- /dev/null +++ b/controllers/TwitterController.php @@ -0,0 +1,121 @@ + [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['post'], + ], + ], + ]; + } + + /** + * Lists all Twitter models. + * @return mixed + */ + public function actionIndex() + { + $searchModel = new TwitterSearch(); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single Twitter model. + * @param integer $id + * @return mixed + */ + public function actionView($id) + { + return $this->render('view', [ + 'model' => $this->findModel($id), + ]); + } + + /** + * Creates a new Twitter model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return mixed + */ + public function actionCreate() + { + $model = new Twitter(); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } else { + return $this->render('create', [ + 'model' => $model, + ]); + } + } + + /** + * Updates an existing Twitter model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param integer $id + * @return mixed + */ + public function actionUpdate($id) + { + $model = $this->findModel($id); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } else { + return $this->render('update', [ + 'model' => $model, + ]); + } + } + + /** + * Deletes an existing Twitter model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param integer $id + * @return mixed + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the Twitter model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param integer $id + * @return Twitter the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = Twitter::findOne($id)) !== null) { + return $model; + } else { + throw new NotFoundHttpException('The requested page does not exist.'); + } + } +} diff --git a/migrations/m150309_174014_create_twitter_table.php b/migrations/m150309_174014_create_twitter_table.php new file mode 100644 index 0000000..cae827b --- /dev/null +++ b/migrations/m150309_174014_create_twitter_table.php @@ -0,0 +1,35 @@ +db->driverName === 'mysql') { + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; + } + + $this->createTable('{{%twitter}}', [ + 'id' => Schema::TYPE_PK, + 'moment_id' => Schema::TYPE_INTEGER . ' NOT NULL', + 'tweet_id' => Schema::TYPE_BIGINT . ' NOT NULL', + 'twitter_id' => Schema::TYPE_BIGINT . ' NOT NULL', + 'screen_name' => Schema::TYPE_STRING . ' NOT NULL DEFAULT 0', + 'text' => Schema::TYPE_TEXT . ' NOT NULL ', + 'tweeted_at' => Schema::TYPE_INTEGER . ' NOT NULL', + 'created_at' => Schema::TYPE_INTEGER . ' NOT NULL', + 'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL', + ], $tableOptions); + $this->addForeignKey('fk_twitter_moment', '{{%twitter}}', 'moment_id', '{{%moment}}', 'id', 'CASCADE', 'CASCADE'); + } + + + public function down() + { + $this->dropForeignKey('fk_twitter_moment','{{%twitter}}'); + $this->dropTable('{{%twitter}}'); + } +} diff --git a/models/Moment.php b/models/Moment.php index b9a314f..4b68899 100644 --- a/models/Moment.php +++ b/models/Moment.php @@ -6,6 +6,7 @@ use yii\db\ActiveRecord; use app\models\Gram; use Instagram; +use TwitterAPIExchange; /** * This is the model class for table "Moment". @@ -58,6 +59,11 @@ public function getGrams() { return $this->hasMany(Gram::className(), ['moment_id' => 'id']); } + + public function getTwitters() + { + return $this->hasMany(Twitter::className(), ['moment_id' => 'id']); + } /** * @inheritdoc @@ -126,9 +132,84 @@ public function searchInstagram() { $i = new Gram(); $i->add($this->id,$m->user->username,$m->link,$m->created_time,$m->images->thumbnail->url,$caption); } } - + + public function searchTwitter() { + // Load your Twitter application keys + $settings = array( + 'oauth_access_token' => \Yii::$app->params['twitter']['oauth_token'], + 'oauth_access_token_secret' => \Yii::$app->params['twitter']['oauth_secret'], + 'consumer_key' => \Yii::$app->params['twitter']['key'], + 'consumer_secret' => \Yii::$app->params['twitter']['secret'], + ); + // Connect to Twitter + $twitter = new TwitterAPIExchange($settings); + // Query settings for search + $url = 'https://api.twitter.com/1.1/search/tweets.json'; + $requestMethod = 'GET'; + // rate limit of 180 queries + $limit = 180; + $query_count=1; + $count = 100; + $result_type = 'recent'; + // calculate valid timestamp range + $valid_start = $this->start_at; + // $until_date and $valid_end = // start time + duration + $valid_end = $this->start_at + ($this->duration*60); + $until_date = date('Y-m-d',$valid_end); + $distance_km = $this->distance/1000; // distance in km + // Unused: &since=$since_date + // $since_date = '2015-03-05'; + // Perform first query with until_date + $getfield ="?result_type=$result_type&geocode=".$this->latitude.",".$this->longitude.",".$distance_km."mi&include_entities=false&until=$until_date&count=$count"; + $tweets = json_decode($twitter->setGetfield($getfield) + ->buildOauth($url, $requestMethod) + ->performRequest()); + var_dump($tweets); + die(); + $max_id = 0; + echo 'Count Statuses: '.count($tweets->statuses).'
'; + echo 'Max Tweet Id: '.$max_id.'
'; + foreach ($tweets->statuses as $t) { + // check if tweet in valid time range + if ($t->created_at >= $valid_start && $t->created_at <= $valid_end) + { + // print_r($t);echo "

"; + $i = new Twitter(); $i->add($this->id,$t->id_str,$t->user->id_str,$t->user->screen_name,$t->created_at,(isset($t->text)?$t->text:'')); + } + if ($max_id ==0) { + $max_id = intval($t->id_str); + } else { + $max_id = min($max_id, intval($t->id_str)); + } + } + // Perform all subsequent queries with addition of updated maximum_tweet_id + while ($query_count<=$limit) { + $query_count+=1; + echo 'Request #: '.$query_count.'
'; + // Perform subsequent query with max_id + $getfield ="?result_type=$result_type&geocode=".$this->latitude.",".$this->longitude.",".$distance_km."mi&include_entities=false&max_id=$max_id&count=$count"; + $tweets = json_decode($twitter->setGetfield($getfield) + ->buildOauth($url, $requestMethod) + ->performRequest()); + echo 'Count Statuses: '.count($tweets->statuses).'
'; + echo 'Max Tweet Id: '.$max_id.'
'; + foreach ($tweets->statuses as $t) { + // check if tweet in valid time range + if ($t->created_at >= $valid_start && $t->created_at <= $valid_end) + { + $i = new Twitter(); $i->add($this->id,$t->id_str,$t->user->id_str,$t->user->screen_name,$t->created_at,(isset($t->text)?$t->text:'')); + } else if ($t->created_at < $valid_start) { + // stop querying when earlier than valid_start + break; + } + $max_id = min($max_id,intval($t->id_str))-1; + } + } // end while + } + public static function purge($moment_id) { Gram::deleteAll('moment_id='.$moment_id); + Twitter::deleteAll('moment_id='.$moment_id); } } diff --git a/models/Twitter.php b/models/Twitter.php new file mode 100644 index 0000000..3275784 --- /dev/null +++ b/models/Twitter.php @@ -0,0 +1,101 @@ + [ + 'class' => 'yii\behaviors\TimestampBehavior', + 'attributes' => [ + ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'], + ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'], + ], + ], + ]; + } + + /** + * @inheritdoc + */ + public function rules() + { + return [ + [['moment_id', 'tweet_id', 'twitter_id', 'tweeted_at'], 'required'], + [['moment_id', 'tweet_id', 'twitter_id', 'tweeted_at', 'created_at', 'updated_at'], 'integer'], + [['text'], 'string'], + [['screen_name'], 'string', 'max' => 255] + ]; + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'moment_id' => 'Moment ID', + 'tweet_id' => 'Tweet ID', + 'twitter_id' => 'Twitter ID', + 'screen_name' => 'Screen Name', + 'text' => 'Text', + 'tweeted_at' => 'Tweeted At', + 'created_at' => 'Created At', + 'updated_at' => 'Updated At', + ]; + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getMoment() + { + return $this->hasOne(Moment::className(), ['id' => 'moment_id']); + } + + public function getGrams() + { + return $this->hasMany(Gram::className(), ['moment_id' => 'id']); + } + + public function add($moment_id,$tweet_id,$twitter_id,$screen_name, $tweeted_at,$text) { + if (!Twitter::find()->where(['moment_id' => $moment_id])->andWhere(['tweet_id'=>$tweet_id])->exists()) { + $i = new Twitter(); + $i->moment_id = $moment_id; + $i->tweet_id = $tweet_id; + $i->twitter_id = $twitter_id; + $i->screen_name = $screen_name; + $i->tweeted_at = strtotime($tweeted_at); + $i->text = $text; + $i->save(); + } + } +} diff --git a/models/TwitterSearch.php b/models/TwitterSearch.php new file mode 100644 index 0000000..e260bae --- /dev/null +++ b/models/TwitterSearch.php @@ -0,0 +1,74 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + $query->andFilterWhere([ + 'id' => $this->id, + 'moment_id' => $this->moment_id, + 'tweet_id' => $this->tweet_id, + 'twitter_id' => $this->twitter_id, + 'tweeted_at' => $this->tweeted_at, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]); + + $query->andFilterWhere(['like', 'screen_name', $this->screen_name]) + ->andFilterWhere(['like', 'text', $this->text]) + ->andFilterWhere(['like', 'link', $this->link]); + + return $dataProvider; + } +} diff --git a/views/moment/browse_twitter.php b/views/moment/browse_twitter.php new file mode 100644 index 0000000..77f04a8 --- /dev/null +++ b/views/moment/browse_twitter.php @@ -0,0 +1,51 @@ +title = 'Tweets'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

title) ?>

+ render('_search', ['model' => $searchModel]); ?> + +

+ 'btn btn-success']) ?> +

+ $dataProvider, + 'columns' => [ + [ + 'label' => 'User', + 'attribute' => 'screen_name', + 'format' => 'raw', + 'value' => function ($model) { + return '
'.$model->screen_name.'
'; + }, + ], + [ + 'label' => 'Tweet', + 'attribute' => 'text', + 'format' => 'raw', + 'value' => function ($model) { + return '
'.$model->text.' link
'; + }, + ], + [ + 'label' => 'Created At', + 'attribute' => 'tweeted_at', + 'format' => 'raw', + 'value' => function ($model) { + return '
'.date('M j, Y G:i a',($model->tweeted_at-(8*3600))).'
'; + }, + ], + ], + ]); ?> + +
diff --git a/views/moment/index.php b/views/moment/index.php index d707c9e..9508c7d 100644 --- a/views/moment/index.php +++ b/views/moment/index.php @@ -37,8 +37,11 @@ 'start_at', 'duration', ['class' => 'yii\grid\ActionColumn', - 'template'=>'{instagram} {update} {delete} {purge}', + 'template'=>'{twitter} {instagram} {update} {delete} {purge}', 'buttons'=>[ + 'twitter' => function ($url, $model) { + return Html::a('', '/eyew/moment/twitter?id='.$model->id, ['title' => 'Search Twitter',]); + }, 'instagram' => function ($url, $model) { return Html::a('', '/eyew/moment/instagram?id='.$model->id, ['title' => 'Search Instagram',]); }, diff --git a/views/twitter/_form.php b/views/twitter/_form.php new file mode 100644 index 0000000..6744dc3 --- /dev/null +++ b/views/twitter/_form.php @@ -0,0 +1,39 @@ + + +
+ + + + field($model, 'moment_id')->textInput() ?> + + field($model, 'tweet_id')->textInput() ?> + + field($model, 'twitter_id')->textInput() ?> + + field($model, 'screen_name')->textInput(['maxlength' => 255]) ?> + + field($model, 'text')->textarea(['rows' => 6]) ?> + + field($model, 'link')->textInput(['maxlength' => 255]) ?> + + field($model, 'tweeted_at')->textInput() ?> + + field($model, 'created_at')->textInput() ?> + + field($model, 'updated_at')->textInput() ?> + +
+ isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> +
+ + + +
diff --git a/views/twitter/_search.php b/views/twitter/_search.php new file mode 100644 index 0000000..6e38cba --- /dev/null +++ b/views/twitter/_search.php @@ -0,0 +1,45 @@ + + + diff --git a/views/twitter/create.php b/views/twitter/create.php new file mode 100644 index 0000000..22518e3 --- /dev/null +++ b/views/twitter/create.php @@ -0,0 +1,21 @@ +title = 'Create Twitter'; +$this->params['breadcrumbs'][] = ['label' => 'Twitters', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

title) ?>

+ + render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/views/twitter/index.php b/views/twitter/index.php new file mode 100644 index 0000000..f759bf8 --- /dev/null +++ b/views/twitter/index.php @@ -0,0 +1,43 @@ +title = 'Twitters'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

title) ?>

+ render('_search', ['model' => $searchModel]); ?> + +

+ 'btn btn-success']) ?> +

+ + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + + 'id', + 'moment_id', + 'tweet_id', + 'twitter_id', + 'screen_name', + // 'text:ntext', + // 'link', + // 'tweeted_at', + // 'created_at', + // 'updated_at', + + ['class' => 'yii\grid\ActionColumn'], + ], + ]); ?> + +
diff --git a/views/twitter/update.php b/views/twitter/update.php new file mode 100644 index 0000000..db6b5f1 --- /dev/null +++ b/views/twitter/update.php @@ -0,0 +1,21 @@ +title = 'Update Twitter: ' . ' ' . $model->id; +$this->params['breadcrumbs'][] = ['label' => 'Twitters', 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->id, 'url' => ['view', 'id' => $model->id]]; +$this->params['breadcrumbs'][] = 'Update'; +?> +
+ +

title) ?>

+ + render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/views/twitter/view.php b/views/twitter/view.php new file mode 100644 index 0000000..2eacbb5 --- /dev/null +++ b/views/twitter/view.php @@ -0,0 +1,44 @@ +title = $model->id; +$this->params['breadcrumbs'][] = ['label' => 'Twitters', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

title) ?>

+ +

+ $model->id], ['class' => 'btn btn-primary']) ?> + $model->id], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 'Are you sure you want to delete this item?', + 'method' => 'post', + ], + ]) ?> +

+ + $model, + 'attributes' => [ + 'id', + 'moment_id', + 'tweet_id', + 'twitter_id', + 'screen_name', + 'text:ntext', + 'link', + 'tweeted_at', + 'created_at', + 'updated_at', + ], + ]) ?> + +