From 82d7be323504d3b693aa300a65fac72b03d10006 Mon Sep 17 00:00:00 2001 From: formsdev <136701234+formsdev@users.noreply.github.com> Date: Fri, 13 Oct 2023 15:41:03 +0530 Subject: [PATCH] Allow users to create private form templates (#210) * Allow users to create private form templates * Improve back-end efficiency --------- Co-authored-by: Julien Nahum --- app/Http/Controllers/TemplateController.php | 20 ++- .../Templates/FormTemplateRequest.php | 1 + app/Models/Template.php | 10 ++ app/Models/User.php | 6 + app/Policies/TemplatePolicy.php | 6 +- ..._21_092812_add_creator_id_to_templates.php | 32 ++++ resources/js/components/Navbar.vue | 9 ++ .../templates/FormTemplateModal.vue | 16 +- .../components/pages/forms/show/ExtraMenu.vue | 6 +- .../pages/pricing/CheckoutDetailsModal.vue | 13 +- .../pages/templates/TemplatesList.vue | 141 ++++++++++++++++++ resources/js/pages/templates/my_templates.vue | 44 ++++++ resources/js/pages/templates/show.vue | 20 ++- resources/js/pages/templates/templates.vue | 127 +--------------- resources/js/router/routes.js | 1 + 15 files changed, 307 insertions(+), 145 deletions(-) create mode 100644 database/migrations/2023_09_21_092812_add_creator_id_to_templates.php create mode 100644 resources/js/components/pages/templates/TemplatesList.vue create mode 100644 resources/js/pages/templates/my_templates.vue diff --git a/app/Http/Controllers/TemplateController.php b/app/Http/Controllers/TemplateController.php index 2f60c9b..474d0ad 100644 --- a/app/Http/Controllers/TemplateController.php +++ b/app/Http/Controllers/TemplateController.php @@ -7,6 +7,7 @@ use App\Http\Requests\Templates\FormTemplateRequest; use App\Http\Resources\FormTemplateResource; use App\Models\Template; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; class TemplateController extends Controller { @@ -16,12 +17,16 @@ class TemplateController extends Controller if ($request->offsetExists('limit') && $request->get('limit') > 0) { $limit = (int) $request->get('limit'); } - return FormTemplateResource::collection( - Template::where('publicly_listed', true) - ->orderByDesc('created_at') - ->limit($limit) - ->get() - ); + + $templates = Template::where('publicly_listed', true) + ->when(Auth::check(), function ($query) { + $query->orWhere('creator_id', Auth::id()); + }) + ->orderByDesc('created_at') + ->limit($limit) + ->get(); + + return FormTemplateResource::collection($templates); } public function create(FormTemplateRequest $request) @@ -34,7 +39,8 @@ class TemplateController extends Controller return $this->success([ 'message' => 'Template was created.', - 'template_id' => $template->id + 'template_id' => $template->id, + 'data' => new FormTemplateResource($template) ]); } diff --git a/app/Http/Requests/Templates/FormTemplateRequest.php b/app/Http/Requests/Templates/FormTemplateRequest.php index 60436fe..048377c 100644 --- a/app/Http/Requests/Templates/FormTemplateRequest.php +++ b/app/Http/Requests/Templates/FormTemplateRequest.php @@ -77,6 +77,7 @@ class FormTemplateRequest extends FormRequest } return new Template([ + 'creator_id' => $this->user()?->id ?? null, 'publicly_listed' => $this->publicly_listed, 'name' => $this->name, 'slug' => $this->slug, diff --git a/app/Models/Template.php b/app/Models/Template.php index 22d5c5f..59c42e3 100644 --- a/app/Models/Template.php +++ b/app/Models/Template.php @@ -14,6 +14,7 @@ class Template extends Model use HasFactory, HasSlug; protected $fillable = [ + 'creator_id', 'name', 'slug', 'description', @@ -41,6 +42,15 @@ class Template extends Model 'publicly_listed' => false, ]; + protected $appends = [ + 'share_url', + ]; + + public function getShareUrlAttribute() + { + return url('/form-templates/'.$this->slug); + } + public function setDescriptionAttribute($value) { // Strip out unwanted html diff --git a/app/Models/User.php b/app/Models/User.php index 1161aa2..538136b 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Http\Controllers\SubscriptionController; use App\Models\Forms\Form; +use App\Models\Template; use App\Notifications\ResetPassword; use App\Notifications\VerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -140,6 +141,11 @@ class User extends Authenticatable implements JWTSubject return $this->hasMany(Form::class,'creator_id'); } + public function formTemplates() + { + return $this->hasMany(Template::class, 'creator_id'); + } + /** * ================================= * Oauth Related diff --git a/app/Policies/TemplatePolicy.php b/app/Policies/TemplatePolicy.php index 9a46201..4ad9a94 100644 --- a/app/Policies/TemplatePolicy.php +++ b/app/Policies/TemplatePolicy.php @@ -18,7 +18,7 @@ class TemplatePolicy */ public function create(User $user) { - return $user->admin || $user->template_editor; + return $user !== null; } /** @@ -30,7 +30,7 @@ class TemplatePolicy */ public function update(User $user, Template $template) { - return $user->admin || $user->template_editor; + return $user->admin || $user->template_editor || $template->creator_id === $user->id; } /** @@ -42,6 +42,6 @@ class TemplatePolicy */ public function delete(User $user, Template $template) { - return $user->admin || $user->template_editor; + return $user->admin || $user->template_editor || $template->creator_id === $user->id; } } diff --git a/database/migrations/2023_09_21_092812_add_creator_id_to_templates.php b/database/migrations/2023_09_21_092812_add_creator_id_to_templates.php new file mode 100644 index 0000000..b35a1b1 --- /dev/null +++ b/database/migrations/2023_09_21_092812_add_creator_id_to_templates.php @@ -0,0 +1,32 @@ +foreignIdFor(\App\Models\User::class,'creator_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('templates', function (Blueprint $table) { + $table->dropColumn('creator_id'); + }); + } +}; diff --git a/resources/js/components/Navbar.vue b/resources/js/components/Navbar.vue index 5f766ee..a8dadb7 100644 --- a/resources/js/components/Navbar.vue +++ b/resources/js/components/Navbar.vue @@ -68,6 +68,15 @@ My Forms + + + + + My Templates + + diff --git a/resources/js/components/open/forms/components/templates/FormTemplateModal.vue b/resources/js/components/open/forms/components/templates/FormTemplateModal.vue index 0040818..0ce7f8a 100644 --- a/resources/js/components/open/forms/components/templates/FormTemplateModal.vue +++ b/resources/js/components/open/forms/components/templates/FormTemplateModal.vue @@ -18,13 +18,13 @@

- New template will be create from your form {{ form.title }}. + New template will be create from your form: {{ form.title }}.

- + import Form from 'vform' import store from '~/store' -import { mapState } from 'vuex' +import { mapState, mapGetters } from 'vuex' import axios from 'axios' import QuestionsEditor from './QuestionsEditor.vue' @@ -93,7 +93,7 @@ export default { mounted () { this.templateForm = new Form(this.template ?? { - publicly_listed: true, + publicly_listed: false, name: '', slug: '', short_description: '', @@ -113,6 +113,9 @@ export default { industries: state => state['open/templates'].industries, types: state => state['open/templates'].types }), + ...mapGetters({ + user: 'auth/user' + }), typesOptions () { return Object.values(this.types).map((type) => { return { @@ -153,6 +156,7 @@ export default { if (response.data.message) { this.alertSuccess(response.data.message) } + this.$store.commit('open/templates/addOrUpdate', response.data.data) this.$emit('close') }) }, @@ -162,7 +166,7 @@ export default { if (response.data.message) { this.alertSuccess(response.data.message) } - this.$store.dispatch('open/templates/addOrUpdate', response.data.data) + this.$store.commit('open/templates/addOrUpdate', response.data.data) this.$emit('close') }) }, @@ -173,7 +177,7 @@ export default { this.alertSuccess(response.data.message) } this.$router.push({ name: 'templates' }) - this.$store.dispatch('open/templates/remove', response.data.data) + this.$store.commit('open/templates/remove', this.template) this.$emit('close') }) } diff --git a/resources/js/components/pages/forms/show/ExtraMenu.vue b/resources/js/components/pages/forms/show/ExtraMenu.vue index 4c56933..d59a55a 100644 --- a/resources/js/components/pages/forms/show/ExtraMenu.vue +++ b/resources/js/components/pages/forms/show/ExtraMenu.vue @@ -20,7 +20,7 @@ - @@ -67,7 +67,7 @@ Duplicate form - @@ -117,7 +117,7 @@
- +
diff --git a/resources/js/components/pages/pricing/CheckoutDetailsModal.vue b/resources/js/components/pages/pricing/CheckoutDetailsModal.vue index f2645be..251bccb 100644 --- a/resources/js/components/pages/pricing/CheckoutDetailsModal.vue +++ b/resources/js/components/pages/pricing/CheckoutDetailsModal.vue @@ -44,7 +44,7 @@ export default { watch: { user () { - this.form.email = this.user.email + this.updateUser() }, show () { // Wait for modal to open and focus on first field @@ -59,13 +59,16 @@ export default { }, mounted () { - if (this.user) { - this.form.name = this.user.name - this.form.email = this.user.email - } + this.updateUser() }, methods: { + updateUser() { + if (this.user) { + this.form.name = this.user.name + this.form.email = this.user.email + } + }, saveDetails () { if (this.form.busy) return this.form.put('api/subscription/update-customer-details').then(() => { diff --git a/resources/js/components/pages/templates/TemplatesList.vue b/resources/js/components/pages/templates/TemplatesList.vue new file mode 100644 index 0000000..f3e0258 --- /dev/null +++ b/resources/js/components/pages/templates/TemplatesList.vue @@ -0,0 +1,141 @@ + + + diff --git a/resources/js/pages/templates/my_templates.vue b/resources/js/pages/templates/my_templates.vue new file mode 100644 index 0000000..78d4a25 --- /dev/null +++ b/resources/js/pages/templates/my_templates.vue @@ -0,0 +1,44 @@ + + + diff --git a/resources/js/pages/templates/show.vue b/resources/js/pages/templates/show.vue index f0fa95c..204c79a 100644 --- a/resources/js/pages/templates/show.vue +++ b/resources/js/pages/templates/show.vue @@ -2,7 +2,7 @@