diff --git a/config/feedback.php b/config/feedback.php index ca5d8ed..ea4703c 100644 --- a/config/feedback.php +++ b/config/feedback.php @@ -2,4 +2,13 @@ return [ + /** + * Model class references + */ + 'model_class' => [ + 'participant' => \App\Models\Participant::class, + + 'location' => \App\Models\Location::class, + ] + ]; diff --git a/database/factories/FeedbackFactory.php b/database/factories/FeedbackFactory.php new file mode 100644 index 0000000..a2669ce --- /dev/null +++ b/database/factories/FeedbackFactory.php @@ -0,0 +1,125 @@ +faker->dateTimeBetween('-1 months', 'now'); + if ($this->faker->boolean) { + $messagetext = $this->faker->sentences(5, true); + $submitted = $actiondate; + } else { + $messagetext = null; + $submitted = null; + } + + if ($this->faker->boolean) { + // Opened Email + $opened_at = $actiondate; + $clicked_negative_at = null; + $clicked_semi_negative_at = null; + $clicked_positive_at = null; + $clicked_semi_positive_at = null; + $clicked_review_at = null; + $redirected_at = null; + $message = null; + if ($this->faker->boolean) { + // Positive + if ($this->faker->boolean) { + // Positive + $opened_at = $actiondate; + $clicked_negative_at = null; + $clicked_semi_negative_at = null; + $clicked_positive_at = $actiondate; + $clicked_semi_positive_at = null; + $clicked_review_at = $actiondate; + $redirected_at = $actiondate; + $message = null; + $submitted_at = null; + } else { + // Semi Positive + $opened_at = $actiondate; + $clicked_negative_at = null; + $clicked_semi_negative_at = null; + $clicked_positive_at = null; + $clicked_semi_positive_at = $actiondate; + $clicked_review_at = null; + $redirected_at = null; + $message = $messagetext; + $submitted_at = $submitted; + } + } else { + // Negative + if ($this->faker->boolean) { + // Negative + $opened_at = $actiondate; + $clicked_negative_at = $actiondate; + $clicked_semi_negative_at = null; + $clicked_positive_at = null; + $clicked_semi_positive_at = null; + $clicked_review_at = null; + $redirected_at = null; + $message = $messagetext; + $submitted_at = $submitted; + } else { + // Semi Negative + $opened_at = $actiondate; + $clicked_negative_at = null; + $clicked_semi_negative_at = $actiondate; + $clicked_positive_at = null; + $clicked_semi_positive_at = null; + $clicked_review_at = null; + $redirected_at = null; + $message = $messagetext; + $submitted_at = $submitted; + } + } + } else { + // Not responded + $opened_at = null; + $clicked_negative_at = null; + $clicked_semi_negative_at = null; + $clicked_positive_at = null; + $clicked_semi_positive_at = null; + $clicked_review_at = null; + $redirected_at = null; + $message = null; + $submitted_at = null; + } + + return [ + 'participant_id' => randomOrCreate(config('feedback.model_class.participant'), 'participant_id'), + 'location_id' => randomOrCreate(config('feedback.model_class.location'), 'location_id'), + 'date' => $this->faker->date(), // Should be a day less than emailed_at + 'emailed_at' => $this->faker->dateTimeBetween('-3 months', '-1 months'), + 'email_identifier' => Str::random(100), + 'opened_at' => $opened_at, + 'clicked_negative_at' => $clicked_negative_at, + 'clicked_semi_negative_at' => $clicked_semi_negative_at, + 'clicked_semi_positive_at' => $clicked_semi_positive_at, + 'clicked_positive_at' => $clicked_positive_at, + 'clicked_review_at' => $clicked_review_at, + 'redirected_at' => $redirected_at, + 'message' => $message, + 'submitted_at' => $submitted_at, + ]; + } +} diff --git a/database/migrations/2020_05_11_130000_create_feedbacks_table.php.stub b/database/migrations/2020_05_11_130000_create_feedbacks_table.php.stub new file mode 100644 index 0000000..d56151a --- /dev/null +++ b/database/migrations/2020_05_11_130000_create_feedbacks_table.php.stub @@ -0,0 +1,43 @@ +getTable(); + + $locationModel = config('feedback.model_class.location'); + $locationTable = (new $locationModel)->getTable(); + + $table->id(); + $table->string('token')->index()->unique(); // unique hash for the feedback so can use in links instead of the id + $table->foreignId('participant_id')->index()->references('id')->on($participantTable); + $table->foreignId('location_id')->index()->references('id')->on($locationTable); + $table->date('date')->index(); // date the escape room game was played + $table->dateTime('emailed_at')->nullable(); + $table->string('email_identifier')->nullable()->unique(); // "MessageID" from Postmark or email service needed to track opens since multiple feedbacks could exist and can't track opens to the participant + $table->dateTime('opened_at')->nullable(); + $table->dateTime('clicked_negative_at')->nullable(); + $table->dateTime('clicked_semi_negative_at')->nullable(); + $table->dateTime('clicked_semi_positive_at')->nullable(); + $table->dateTime('clicked_positive_at')->nullable(); + $table->dateTime('clicked_review_at')->nullable(); + $table->dateTime('redirected_at')->nullable(); + $table->text('message')->nullable(); + $table->dateTime('submitted_at')->nullable(); // message submitted datetime + $table->softDeletes(); // Soft delete if email bounces. Also need to soft delete the Participant & update the waiver signature. + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('feedbacks'); + } +} diff --git a/src/FeedbackServiceProvider.php b/src/FeedbackServiceProvider.php index 6812cda..21c5b3a 100644 --- a/src/FeedbackServiceProvider.php +++ b/src/FeedbackServiceProvider.php @@ -19,7 +19,22 @@ public function configurePackage(Package $package): void ->name('feedback') ->hasConfigFile() ->hasViews() - ->hasMigration('create_feedback_table') + ->hasMigration('2020_05_11_130000_create_feedbacks_table') ->hasCommand(FeedbackCommand::class); } + + /** + * Using packageBooted lifecycle hooks to override the migration file name. + * We want to keep the old filename for now. + */ + public function packageBooted() + { + foreach ($this->package->migrationFileNames as $migrationFileName) { + if (! $this->migrationFileExists($migrationFileName)) { + $this->publishes([ + $this->package->basePath("/../database/migrations/{$migrationFileName}.php.stub") => database_path('migrations/' . Str::finish($migrationFileName, '.php')), + ], "{$this->package->name}-migrations"); + } + } + } } diff --git a/src/Models/Feedback.php b/src/Models/Feedback.php new file mode 100644 index 0000000..19a9e9d --- /dev/null +++ b/src/Models/Feedback.php @@ -0,0 +1,54 @@ + 'datetime', + 'opened_at' => 'datetime', + 'clicked_negative_at' => 'datetime', + 'clicked_semi_negative_at' => 'datetime', + 'clicked_semi_positive_at' => 'datetime', + 'clicked_positive_at' => 'datetime', + 'redirected_at' => 'datetime', + 'clicked_review_at' => 'datetime', + 'submitted_at' => 'datetime', + 'date' => 'date', + ]; + + protected static function boot() + { + parent::boot(); + + static::creating(function ($feedback) { + if (empty($feedback->token)) { + $feedback->token = $feedback->location_id . 'L' . mt_rand(1000, 9999) . 'TGER' . mt_rand(1, 999999); + } + }); + } + + public function getRouteKeyName() + { + return 'token'; + } + + public function participant() + { + return $this->belongsTo(config('feedback.model_class.participant'), 'participant_id'); + } + + public function location() + { + return $this->belongsTo(config('feedback.model_class.location'), 'location_id'); + } +}