Asset sync model and endpoints [SCI-9465] (#6399)

This commit is contained in:
Martin Artnik 2023-10-17 11:36:08 +02:00 committed by Martin Artnik
parent 5972140fd0
commit 7376b363a8
9 changed files with 133 additions and 1 deletions

View file

@ -0,0 +1,43 @@
# frozen_string_literal: true
class AssetSyncController < ApplicationController
skip_before_action :authenticate_user!, only: :update
skip_before_action :verify_authenticity_token, only: :update
before_action :authenticate_asset_sync_token!, only: :update
def show
asset = Asset.find_by(params[:asset_id])
head :forbidden unless asset && can_manage_asset?(asset)
asset_sync_token = current_user.asset_sync_tokens.find_or_create_by(asset_id: params[:asset_id])
unless asset_sync_token.token_valid?
asset_sync_token = current_user.asset_sync_tokens.create(asset_id: params[:asset_id])
end
render json: AssetSyncTokenSerializer.new(asset_sync_token).as_json
end
def update
head(:conflict) and return if @asset_sync_token.conflicts?(request.headers['VersionToken'])
@asset.file.attach(io: request.body, filename: @asset.file.filename)
@asset.touch
render json: AssetSyncTokenSerializer.new(@asset_sync_token).as_json
end
# private
def authenticate_asset_sync_token!
@asset_sync_token = AssetSyncToken.find_by(token: request.headers['Authentication'])
head(:unauthorized) and return unless @asset_sync_token&.token_valid?
@asset = @asset_sync_token.asset
@current_user = @asset_sync_token.user
head :forbidden unless can_manage_asset?(@asset)
end
end

View file

@ -44,6 +44,7 @@ class Asset < ApplicationRecord
dependent: :nullify
has_many :report_elements, inverse_of: :asset, dependent: :destroy
has_one :asset_text_datum, inverse_of: :asset, dependent: :destroy
has_many :asset_sync_tokens, dependent: :destroy
scope :sort_assets, lambda { |sort_value = 'new'|
sort = case sort_value

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
class AssetSyncToken < ApplicationRecord
belongs_to :user
belongs_to :asset
after_initialize :generate_token
after_initialize :set_default_expiration
validates :token, uniqueness: true, presence: true
def version_token
asset.updated_at.to_i.to_s
end
def token_valid?
!revoked_at? && expires_at > Time.current
end
def conflicts?(token)
version_token != token
end
private
def generate_token
self.token ||= SecureRandom.urlsafe_base64(32)
end
def set_default_expiration
self.expires_at ||= Constants::ASSET_SYNC_TOKEN_EXPIRATION.from_now
end
end

View file

@ -318,6 +318,7 @@ class User < ApplicationRecord
has_many :access_tokens, class_name: 'Doorkeeper::AccessToken',
foreign_key: :resource_owner_id,
dependent: :delete_all
has_many :asset_sync_tokens, dependent: :destroy
has_many :hidden_repository_cell_reminders, dependent: :destroy

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
class AssetSyncTokenSerializer < ActiveModel::Serializer
include Rails.application.routes.url_helpers
attributes :url, :asset_id, :filename, :token, :asset_id, :version_token, :checksum
def checksum
object.asset.file.checksum
end
def url
object.asset.file.url
end
def filename
object.asset.file.filename
end
end

View file

@ -416,6 +416,8 @@ class Constants
FAST_STATUS_POLLING_INTERVAL = 5000
SLOW_STATUS_POLLING_INTERVAL = 10000
ASSET_SYNC_TOKEN_EXPIRATION = 1.year
# ) \ / (
# /|\ )\_/( /|\
# * / | \ (/\|/\) / | \ *

View file

@ -1002,6 +1002,9 @@ Rails.application.routes.draw do
end
end
get 'asset_sync/:asset_id', to: 'asset_sync#show'
put 'asset_sync', to: 'asset_sync#update'
post 'global_activities', to: 'global_activities#index'
constraints WopiSubdomain do

View file

@ -0,0 +1,15 @@
# frozen_string_literal: true
class CreateAssetSyncTokens < ActiveRecord::Migration[7.0]
def change
create_table :asset_sync_tokens do |t|
t.references :user, null: false, foreign_key: true
t.references :asset, null: false, foreign_key: true
t.string :token, index: { unique: true }
t.timestamp :expires_at
t.timestamp :revoked_at
t.timestamps
end
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_10_03_114337) do
ActiveRecord::Schema[7.0].define(version: 2023_10_06_141428) do
# These are extensions that must be enabled in order to support this database
enable_extension "btree_gist"
enable_extension "pg_trgm"
@ -76,6 +76,19 @@ ActiveRecord::Schema[7.0].define(version: 2023_10_03_114337) do
t.datetime "updated_at", null: false
end
create_table "asset_sync_tokens", force: :cascade do |t|
t.bigint "user_id", null: false
t.bigint "asset_id", null: false
t.string "token"
t.datetime "expires_at", precision: nil
t.datetime "revoked_at", precision: nil
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["asset_id"], name: "index_asset_sync_tokens_on_asset_id"
t.index ["token"], name: "index_asset_sync_tokens_on_token", unique: true
t.index ["user_id"], name: "index_asset_sync_tokens_on_user_id"
end
create_table "asset_text_data", force: :cascade do |t|
t.text "data", null: false
t.bigint "asset_id", null: false
@ -1309,6 +1322,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_10_03_114337) do
add_foreign_key "activities", "my_modules"
add_foreign_key "activities", "projects"
add_foreign_key "activities", "users", column: "owner_id"
add_foreign_key "asset_sync_tokens", "assets"
add_foreign_key "asset_sync_tokens", "users"
add_foreign_key "asset_text_data", "assets"
add_foreign_key "assets", "users", column: "created_by_id"
add_foreign_key "assets", "users", column: "last_modified_by_id"