mirror of
https://github.com/mastodon/mastodon.git
synced 2025-11-27 10:00:50 +00:00
Add shared context for API authentication (#36981)
This commit is contained in:
parent
1bc13609ab
commit
b16452dd99
|
|
@ -25,3 +25,9 @@ end
|
|||
Fabricator(:owner_user, from: :user) do
|
||||
role UserRole.find_by(name: 'Owner')
|
||||
end
|
||||
|
||||
Fabricator(:private_user, from: :user) do
|
||||
account_attributes do
|
||||
{ discoverable: false, locked: true, indexable: false }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'credentials API' do
|
||||
let(:user) { Fabricate(:user, account_attributes: { discoverable: false, locked: true, indexable: false }) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:accounts write:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :private_user, oauth_scopes: 'read:accounts write:accounts'
|
||||
|
||||
describe 'GET /api/v1/accounts/verify_credentials' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Accounts Pins API' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'write:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'write:accounts'
|
||||
|
||||
let(:kevin) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Accounts Familiar Followers API' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:follows' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:follows'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
describe 'GET /api/v1/accounts/familiar_followers' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'account featured tags API' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:accounts'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
describe 'GET /api/v1/accounts/:id/featured_tags' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API V1 Accounts FollowerAccounts' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:accounts'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:alice) { Fabricate(:account) }
|
||||
let(:bob) { Fabricate(:account) }
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API V1 Accounts FollowingAccounts' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:accounts'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:alice) { Fabricate(:account) }
|
||||
let(:bob) { Fabricate(:account) }
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Accounts Identity Proofs API' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:accounts'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
describe 'GET /api/v1/accounts/identity_proofs' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Accounts Lists API' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:lists' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:lists'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:list) { Fabricate(:list, account: user.account) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Accounts Lookup API' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:accounts'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
describe 'GET /api/v1/accounts/lookup' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Accounts Notes API' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'write:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'write:accounts'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:comment) { 'foo' }
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@ RSpec.describe 'GET /api/v1/accounts/relationships' do
|
|||
get '/api/v1/accounts/relationships', headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:follows' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:follows'
|
||||
|
||||
let(:simon) { Fabricate(:account) }
|
||||
let(:lewis) { Fabricate(:account) }
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Accounts Search API' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:accounts'
|
||||
|
||||
describe 'GET /api/v1/accounts/search' do
|
||||
it 'returns http success' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API V1 Accounts Statuses' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:statuses' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:statuses'
|
||||
|
||||
describe 'GET /api/v1/accounts/:account_id/statuses' do
|
||||
it 'returns expected headers', :aggregate_failures do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe '/api/v1/accounts' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { '' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication'
|
||||
|
||||
describe 'GET /api/v1/accounts?id[]=:id' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Account actions' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:write admin:write:accounts' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:write admin:write:accounts'
|
||||
|
||||
shared_examples 'a successful notification delivery' do
|
||||
it 'notifies the user about the action taken', :inline_jobs do
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Accounts' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read:accounts admin:write:accounts' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read:accounts admin:write:accounts'
|
||||
|
||||
describe 'GET /api/v1/admin/accounts' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Canonical Email Blocks' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'admin:read:canonical_email_blocks admin:write:canonical_email_blocks' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read:canonical_email_blocks admin:write:canonical_email_blocks'
|
||||
|
||||
describe 'GET /api/v1/admin/canonical_email_blocks' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Admin Dimensions' do
|
||||
let(:user) { Fabricate(:admin_user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
describe 'GET /api/v1/admin/dimensions' do
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Domain Allows' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read admin:write'
|
||||
|
||||
describe 'GET /api/v1/admin/domain_allows' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Domain Blocks' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read:domain_blocks admin:write:domain_blocks' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read:domain_blocks admin:write:domain_blocks'
|
||||
|
||||
describe 'GET /api/v1/admin/domain_blocks' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,12 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Email Domain Blocks' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:scopes) { 'admin:read:email_domain_blocks admin:write:email_domain_blocks' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read:email_domain_blocks admin:write:email_domain_blocks'
|
||||
|
||||
describe 'GET /api/v1/admin/email_domain_blocks' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'IP Blocks' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'admin:read:ip_blocks admin:write:ip_blocks' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read:ip_blocks admin:write:ip_blocks'
|
||||
|
||||
describe 'GET /api/v1/admin/ip_blocks' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Admin Measures' do
|
||||
let(:user) { Fabricate(:admin_user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
let(:account) { Fabricate(:account) }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
keys: %w(instance_accounts instance_follows instance_followers),
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Reports' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read:reports admin:write:reports' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read:reports admin:write:reports'
|
||||
|
||||
describe 'GET /api/v1/admin/reports' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Admin Retention' do
|
||||
let(:user) { Fabricate(:admin_user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
describe 'GET /api/v1/admin/retention' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Tags' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read admin:write'
|
||||
|
||||
let(:tag) { Fabricate(:tag) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Links' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read admin:write'
|
||||
|
||||
describe 'GET /api/v1/admin/trends/links' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,11 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API V1 Admin Trends Links Preview Card Providers' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read admin:write'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:preview_card_provider) { Fabricate(:preview_card_provider) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,10 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API V1 Admin Trends Statuses' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read admin:write'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:status) { Fabricate(:status) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/admin/trends/statuses' do
|
||||
it 'returns http success' do
|
||||
|
|
|
|||
|
|
@ -3,13 +3,10 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API V1 Admin Trends Tags' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
include_context 'with API authentication', user_fabricator: :admin_user, oauth_scopes: 'admin:read admin:write'
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:tag) { Fabricate(:tag) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/admin/trends/tags' do
|
||||
it 'returns http success' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API V1 Announcements' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read'
|
||||
|
||||
let!(:announcement) { Fabricate(:announcement) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API V1 Annual Reports' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication'
|
||||
|
||||
describe 'GET /api/v1/annual_reports' do
|
||||
context 'when not authorized' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Blocks' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:blocks' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:blocks'
|
||||
|
||||
describe 'GET /api/v1/blocks' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Bookmarks' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:bookmarks' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:bookmarks'
|
||||
|
||||
describe 'GET /api/v1/bookmarks' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API V1 Conversations' do
|
||||
include_context 'with API authentication', oauth_scopes: 'read:statuses'
|
||||
|
||||
let!(:user) { Fabricate(:user, account_attributes: { username: 'alice' }) }
|
||||
let(:scopes) { 'read:statuses' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
let(:other) { Fabricate(:user) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Custom Emojis' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication'
|
||||
|
||||
describe 'GET /api/v1/custom_emojis' do
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Directories API' do
|
||||
include_context 'with API authentication', oauth_scopes: 'read:follows'
|
||||
|
||||
let(:user) { Fabricate(:user, confirmed_at: nil) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:follows' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/directories' do
|
||||
context 'with no params' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Domain blocks' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:blocks write:blocks' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:blocks write:blocks'
|
||||
|
||||
describe 'GET /api/v1/domain_blocks' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Endorsements' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication'
|
||||
|
||||
describe 'GET /api/v1/endorsements' do
|
||||
context 'when not authorized' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Favourites' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:favourites' }
|
||||
let(:headers) { { Authorization: "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:favourites'
|
||||
|
||||
describe 'GET /api/v1/favourites' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'FeaturedTags' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:accounts write:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:accounts write:accounts'
|
||||
|
||||
describe 'GET /api/v1/featured_tags' do
|
||||
context 'with wrong scope' do
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API V1 Filters' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication'
|
||||
|
||||
describe 'GET /api/v1/filters' do
|
||||
let(:scopes) { 'read:filters' }
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Follow requests' do
|
||||
include_context 'with API authentication', oauth_scopes: 'read:follows write:follows'
|
||||
|
||||
let(:user) { Fabricate(:user, account_attributes: { locked: true }) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:follows write:follows' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/follow_requests' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Followed tags' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:follows' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:follows'
|
||||
|
||||
describe 'GET /api/v1/followed_tags' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Instances' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication'
|
||||
|
||||
describe 'GET /api/v1/instance' do
|
||||
context 'when not logged in' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Lists' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:lists write:lists' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:lists write:lists'
|
||||
|
||||
describe 'GET /api/v1/lists' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'API Markers' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:statuses write:statuses' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:statuses write:statuses'
|
||||
|
||||
describe 'GET /api/v1/markers' do
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Media' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'write:media' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'write:media'
|
||||
|
||||
describe 'GET /api/v1/media/:id' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Mutes' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:mutes' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:mutes'
|
||||
|
||||
describe 'GET /api/v1/mutes' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Notifications' do
|
||||
include_context 'with API authentication', oauth_scopes: 'read:notifications write:notifications'
|
||||
|
||||
let(:user) { Fabricate(:user, account_attributes: { username: 'alice' }) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:notifications write:notifications' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/notifications/unread_count', :inline_jobs do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Polls' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:statuses' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:statuses'
|
||||
|
||||
describe 'GET /api/v1/polls/:id' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Preferences' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication'
|
||||
|
||||
describe 'GET /api/v1/preferences' do
|
||||
context 'when not authorized' do
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Deleting profile images' do
|
||||
include_context 'with API authentication', oauth_scopes: 'write:accounts'
|
||||
|
||||
let(:account) do
|
||||
Fabricate(
|
||||
:account,
|
||||
|
|
@ -10,9 +12,7 @@ RSpec.describe 'Deleting profile images' do
|
|||
header: fixture_file_upload('attachment.jpg', 'image/jpeg')
|
||||
)
|
||||
end
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: account.user.id, scopes: scopes) }
|
||||
let(:scopes) { 'write:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
let(:user) { account.user }
|
||||
|
||||
describe 'DELETE /api/v1/profile' do
|
||||
context 'when deleting an avatar' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Reports' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'write:reports' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'write:reports'
|
||||
|
||||
describe 'POST /api/v1/reports' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Scheduled Statuses' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication'
|
||||
|
||||
describe 'GET /api/v1/scheduled_statuses' do
|
||||
context 'when not authorized' do
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ require 'rails_helper'
|
|||
|
||||
RSpec.describe '/api/v1/statuses' do
|
||||
context 'with an oauth token' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
include_context 'with API authentication'
|
||||
|
||||
let(:client_app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: client_app, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/statuses?id[]=:id' do
|
||||
let(:status) { Fabricate(:status) }
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Suggestions' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read'
|
||||
|
||||
describe 'GET /api/v1/suggestions' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Tags' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'write:follows' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'write:follows'
|
||||
|
||||
describe 'GET /api/v1/tags/:id' do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'AsyncRefreshes' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication'
|
||||
|
||||
let(:job) { AsyncRefresh.new('test_job') }
|
||||
|
||||
describe 'GET /api/v1_alpha/async_refreshes/:id' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Filters' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:filters write:filters' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:filters write:filters'
|
||||
|
||||
shared_examples 'unauthorized for invalid token' do
|
||||
let(:headers) { { 'Authorization' => '' } }
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Instances' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication'
|
||||
|
||||
describe 'GET /api/v2/instance' do
|
||||
context 'when logged out' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Media API', :attachment_processing do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'write' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'write'
|
||||
|
||||
describe 'POST /api/v2/media' do
|
||||
context 'when small media format attachment is processed immediately' do
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Notifications' do
|
||||
include_context 'with API authentication', oauth_scopes: 'read:notifications write:notifications'
|
||||
|
||||
let(:user) { Fabricate(:user, account_attributes: { username: 'alice' }) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:notifications write:notifications' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v2/notifications/unread_count', :inline_jobs do
|
||||
subject do
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@ require 'rails_helper'
|
|||
|
||||
RSpec.describe 'Search API' do
|
||||
context 'with token' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:search' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read:search'
|
||||
|
||||
describe 'GET /api/v2/search' do
|
||||
let!(:bob) { Fabricate(:account, username: 'bob_test') }
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Suggestions API' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read'
|
||||
|
||||
describe 'GET /api/v2/suggestions' do
|
||||
let(:bob) { Fabricate(:account) }
|
||||
|
|
|
|||
|
|
@ -65,9 +65,7 @@ RSpec.describe '/api/web/embed' do
|
|||
end
|
||||
|
||||
context 'with an API token' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
include_context 'with API authentication', oauth_scopes: 'read'
|
||||
|
||||
context 'when the requested status is local' do
|
||||
let(:id) { status.id }
|
||||
|
|
|
|||
8
spec/support/api_authentication.rb
Normal file
8
spec/support/api_authentication.rb
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_context 'with API authentication' do |oauth_scopes: '', user_fabricator: :user|
|
||||
let(:user) { Fabricate(user_fabricator) }
|
||||
let(:scopes) { oauth_scopes }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
end
|
||||
|
|
@ -13,6 +13,7 @@ end
|
|||
|
||||
RSpec.shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
let(:user) { Fabricate(:user, role:) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
# Some examples have a subject which needs to be called to make a request
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user