mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-04 10:54:30 +08:00
Asset sync model and endpoints [SCI-9465] (#6399)
This commit is contained in:
parent
5972140fd0
commit
7376b363a8
9 changed files with 133 additions and 1 deletions
43
app/controllers/asset_sync_controller.rb
Normal file
43
app/controllers/asset_sync_controller.rb
Normal 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
|
|
@ -44,6 +44,7 @@ class Asset < ApplicationRecord
|
||||||
dependent: :nullify
|
dependent: :nullify
|
||||||
has_many :report_elements, inverse_of: :asset, dependent: :destroy
|
has_many :report_elements, inverse_of: :asset, dependent: :destroy
|
||||||
has_one :asset_text_datum, 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'|
|
scope :sort_assets, lambda { |sort_value = 'new'|
|
||||||
sort = case sort_value
|
sort = case sort_value
|
||||||
|
|
33
app/models/asset_sync_token.rb
Normal file
33
app/models/asset_sync_token.rb
Normal 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
|
|
@ -318,6 +318,7 @@ class User < ApplicationRecord
|
||||||
has_many :access_tokens, class_name: 'Doorkeeper::AccessToken',
|
has_many :access_tokens, class_name: 'Doorkeeper::AccessToken',
|
||||||
foreign_key: :resource_owner_id,
|
foreign_key: :resource_owner_id,
|
||||||
dependent: :delete_all
|
dependent: :delete_all
|
||||||
|
has_many :asset_sync_tokens, dependent: :destroy
|
||||||
|
|
||||||
has_many :hidden_repository_cell_reminders, dependent: :destroy
|
has_many :hidden_repository_cell_reminders, dependent: :destroy
|
||||||
|
|
||||||
|
|
19
app/serializers/asset_sync_token_serializer.rb
Normal file
19
app/serializers/asset_sync_token_serializer.rb
Normal 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
|
|
@ -416,6 +416,8 @@ class Constants
|
||||||
FAST_STATUS_POLLING_INTERVAL = 5000
|
FAST_STATUS_POLLING_INTERVAL = 5000
|
||||||
SLOW_STATUS_POLLING_INTERVAL = 10000
|
SLOW_STATUS_POLLING_INTERVAL = 10000
|
||||||
|
|
||||||
|
ASSET_SYNC_TOKEN_EXPIRATION = 1.year
|
||||||
|
|
||||||
# ) \ / (
|
# ) \ / (
|
||||||
# /|\ )\_/( /|\
|
# /|\ )\_/( /|\
|
||||||
# * / | \ (/\|/\) / | \ *
|
# * / | \ (/\|/\) / | \ *
|
||||||
|
|
|
@ -1002,6 +1002,9 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
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'
|
post 'global_activities', to: 'global_activities#index'
|
||||||
|
|
||||||
constraints WopiSubdomain do
|
constraints WopiSubdomain do
|
||||||
|
|
15
db/migrate/20231006141428_create_asset_sync_tokens.rb
Normal file
15
db/migrate/20231006141428_create_asset_sync_tokens.rb
Normal 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
|
17
db/schema.rb
17
db/schema.rb
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# 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
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "btree_gist"
|
enable_extension "btree_gist"
|
||||||
enable_extension "pg_trgm"
|
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
|
t.datetime "updated_at", null: false
|
||||||
end
|
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|
|
create_table "asset_text_data", force: :cascade do |t|
|
||||||
t.text "data", null: false
|
t.text "data", null: false
|
||||||
t.bigint "asset_id", 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", "my_modules"
|
||||||
add_foreign_key "activities", "projects"
|
add_foreign_key "activities", "projects"
|
||||||
add_foreign_key "activities", "users", column: "owner_id"
|
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 "asset_text_data", "assets"
|
||||||
add_foreign_key "assets", "users", column: "created_by_id"
|
add_foreign_key "assets", "users", column: "created_by_id"
|
||||||
add_foreign_key "assets", "users", column: "last_modified_by_id"
|
add_foreign_key "assets", "users", column: "last_modified_by_id"
|
||||||
|
|
Loading…
Add table
Reference in a new issue