Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: apis for tag, video #1

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ end

spree_version = '>= 4.5'
gem 'spree', spree_version
gem 'spree_auth_devise', spree_version
gem 'rails-controller-testing'

gemspec
94 changes: 94 additions & 0 deletions app/controllers/spree/api/v2/storefront/videos_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
module Spree
module Api
module V2
module Storefront
class VideosController < ::Spree::Api::V2::ResourceController
include Spree::Api::V2::CollectionOptionsHelpers
before_action :load_product, only: [:create, :index]
before_action :load_video, only: [:add_tag, :remove_tag, :destroy]
before_action :require_spree_current_user, only: [:add_tag, :remove_tag, :destroy, :create]

def create
@video = @product.videos.new(video_params)

if params[:video][:file].present? && @video.save
render_serialized_payload { serialize_resource(@video) }
else
render_error_payload(@video.errors)
end
end

def destroy
if @video.destroy
render_serialized_payload { serialize_resource(@video) }
else
render_error_payload(@video.errors)
end
end

def add_tag
tag = Spree::Tag.find_or_create_by(name: params[:video][:tag_name], product: @video.product)

unless @video.tags.include?(tag)
@video.tags << tag
end

render_serialized_payload { serialize_resource(@video) }
end

def remove_tag
tag = @video.tags.find_by(name: params[:video][:tag_name])

if tag && @video.tags.destroy(tag)
render_serialized_payload { serialize_resource(@video) }
else
render_error_payload(@video.errors)
end
end

def index
if params[:video][:tag_name].present?
tag = Spree::Tag.find_by(name: params[:video][:tag_name], product: @product)
@videos = tag ? tag.videos : []
else
@videos = @product.videos
end

render_serialized_payload { serialize_resource(collection) }
end

private

def load_video
@video = Spree::Video.find(params[:id])
end

def collection
collection_paginator.new(@videos, params).call
end

def load_product
@product = Spree::Product.find(params[:product_id])
end

def video_params
params.require(:video).permit(permitted_video_attributes)
end

def permitted_video_attributes
permitted_attributes.video_attributes
end

def resource_serializer
Spree::Api::V2::VideoSerializer
end

def collection_serializer
Spree::V2::Storefront::VideoSerializer
end

end
end
end
end
end
11 changes: 11 additions & 0 deletions app/models/spree/product_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Add access to reviews/ratings to the product model
module Spree
module ProductDecorator
def self.prepended(base)
base.has_many :videos
base.has_many :tags, through: :videos
end

::Spree::Product.prepend self if ::Spree::Product.included_modules.exclude?(self)
end
end
8 changes: 8 additions & 0 deletions app/models/spree/tag.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Spree
class Tag < ActiveRecord::Base
belongs_to :product, class_name: 'Spree::Product'

has_many :video_tags
has_many :videos, through: :video_tags
end
end
40 changes: 40 additions & 0 deletions app/models/spree/video.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module Spree
class Video < ActiveRecord::Base
belongs_to :product, class_name: 'Spree::Product'
has_many :video_tags
has_many :tags, through: :video_tags

has_one_attached :file

validate :acceptable_video
after_save :generate_video_url, if: :file_attached_and_url_changed?

private

def acceptable_video
return unless file.attached?

acceptable_types = [
"video/mp4",
"video/mpeg",
"video/quicktime",
"video/webm",
"video/ogg",
"video/av1"
]
unless acceptable_types.include?(file.content_type)
errors.add(:file, "must be a MP4, MPEG, QuickTime, WebM, Ogg, or AV1 video")
end
end

def generate_video_url
if file.attached? && url != file.url
self.update(url: file.url)
end
end

def file_attached_and_url_changed?
file.attached? && url != file.url
end
end
end
6 changes: 6 additions & 0 deletions app/models/spree/video_tag.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Spree
class VideoTag < ActiveRecord::Base
belongs_to :video, class_name: 'Spree::Video'
belongs_to :tag, class_name: 'Spree::Tag'
end
end
9 changes: 9 additions & 0 deletions app/serializers/spree/api/v2/tag_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Spree
module Api
module V2
class TagSerializer < BaseSerializer
attributes :id, :name
end
end
end
end
11 changes: 11 additions & 0 deletions app/serializers/spree/api/v2/video_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Spree
module Api
module V2
class VideoSerializer < BaseSerializer
attributes :id, :url, :product_id, :created_at

has_many :tags, serializer: :tag
end
end
end
end
8 changes: 8 additions & 0 deletions config/initializers/spree_permitted_attributes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Spree
module PermittedAttributes
ATTRIBUTES += %i[video_attributes]
mattr_reader *ATTRIBUTES

@@video_attributes = [:tag_name, :product_id, :url, :file]
sushil-truemark marked this conversation as resolved.
Show resolved Hide resolved
end
end
18 changes: 17 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
Spree::Core::Engine.add_routes do
# Add your extension routes here
namespace :api do
namespace :v2 do
namespace :storefront do
resources :products, only: [] do
resources :videos, only: [:create, :destroy] do
collection do
get :index # To list videos by tag
end
member do
post :add_tag
delete :remove_tag
end
end
end
end
end
end
end
10 changes: 10 additions & 0 deletions db/migrate/20240902083107_create_spree_videos.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateSpreeVideos < SpreeExtension::Migration[4.2]
def change
create_table :spree_videos do |t|
t.string :url
t.references :product, foreign_key: { to_table: :spree_products }, index: true

t.timestamps null: false
end
end
end
12 changes: 12 additions & 0 deletions db/migrate/20240902085023_create_spree_tags.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateSpreeTags < SpreeExtension::Migration[4.2]
def change
create_table :spree_tags do |t|
t.string :name, null: false
t.references :product, foreign_key: { to_table: :spree_products }, index: true

t.timestamps null: false
end

add_index :spree_tags, [:product_id, :name], unique: true
end
end
12 changes: 12 additions & 0 deletions db/migrate/20240902085646_create_spree_video_tags.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateSpreeVideoTags < SpreeExtension::Migration[4.2]
def change
create_table :spree_video_tags do |t|
t.integer :video_id
t.integer :tag_id

t.timestamps null: false
end

add_index :spree_video_tags, [:video_id, :tag_id], unique: true
end
end
4 changes: 2 additions & 2 deletions spree_product_videos.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ Gem::Specification.new do |s|
s.description = 'Add (optional) extension description here'
s.required_ruby_version = '>= 3.0'

s.author = 'You'
s.email = 'you@example.com'
s.author = 'truemark'
s.email = 'sushil@truemark.com.np'
s.homepage = 'https://github.com/your-github-handle/spree_product_videos'
s.license = 'BSD-3-Clause'

Expand Down