mirror of
https://github.com/System-End/hackatime.git
synced 2026-04-19 16:38:23 +00:00
* Fix data export + Capybara * Continue? * A ton of system tests :D + test cleanup * More system tests * Add placeholder keys for tests? * Get rid of the double-query! * Speed up CI Chrome setup by avoiding snap installs * Pin CI Chrome version to reduce system test flakiness * Stabilize integrations settings system test interaction
641 lines
22 KiB
Ruby
641 lines
22 KiB
Ruby
require 'swagger_helper'
|
|
|
|
RSpec.describe 'Api::Admin::V1::UserUtils', type: :request do
|
|
path '/api/admin/v1/user/info_batch' do
|
|
get('Get user info batch') do
|
|
tags 'Admin Utils'
|
|
description 'Get info for multiple users.'
|
|
security [ AdminToken: [] ]
|
|
produces 'application/json'
|
|
|
|
parameter name: :ids, in: :query, schema: { type: :array, items: { type: :integer } }, description: 'User IDs'
|
|
|
|
response(200, 'successful') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:u1) do
|
|
u = User.create!(username: 'u1')
|
|
EmailAddress.create!(user: u, email: 'u1@example.com')
|
|
u
|
|
end
|
|
let(:u2) do
|
|
u = User.create!(username: 'u2')
|
|
EmailAddress.create!(user: u, email: 'u2@example.com')
|
|
u
|
|
end
|
|
let(:ids) { [ u1.id, u2.id ] }
|
|
schema type: :object,
|
|
properties: {
|
|
users: {
|
|
type: :array,
|
|
items: {
|
|
type: :object,
|
|
properties: {
|
|
id: { type: :integer },
|
|
username: { type: :string },
|
|
display_name: { type: :string },
|
|
slack_uid: { type: :string, nullable: true },
|
|
slack_username: { type: :string, nullable: true },
|
|
github_username: { type: :string, nullable: true },
|
|
timezone: { type: :string, nullable: true },
|
|
country_code: { type: :string, nullable: true },
|
|
trust_level: { type: :string },
|
|
avatar_url: { type: :string, nullable: true },
|
|
slack_avatar_url: { type: :string, nullable: true },
|
|
github_avatar_url: { type: :string, nullable: true }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
run_test! do |response|
|
|
expect(response).to have_http_status(:ok)
|
|
body = JSON.parse(response.body)
|
|
expect(body["users"]).to be_an(Array)
|
|
returned_ids = body["users"].map { |entry| entry["id"] }
|
|
expect(returned_ids & [ u1.id, u2.id ]).not_to be_empty
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/info' do
|
|
get('Get user info') do
|
|
tags 'Admin Utils'
|
|
description 'Get detailed info for a single user.'
|
|
security [ AdminToken: [] ]
|
|
produces 'application/json'
|
|
|
|
parameter name: :user_id, in: :query, type: :string, description: 'User ID'
|
|
|
|
response(200, 'successful') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user) do
|
|
u = User.create!(username: 'info_user')
|
|
EmailAddress.create!(user: u, email: 'info@example.com')
|
|
u
|
|
end
|
|
let(:user_id) { user.id }
|
|
schema type: :object,
|
|
properties: {
|
|
user: {
|
|
type: :object,
|
|
properties: {
|
|
id: { type: :integer },
|
|
username: { type: :string },
|
|
display_name: { type: :string },
|
|
slack_uid: { type: :string, nullable: true },
|
|
slack_username: { type: :string, nullable: true },
|
|
github_username: { type: :string, nullable: true },
|
|
timezone: { type: :string, nullable: true },
|
|
country_code: { type: :string, nullable: true },
|
|
admin_level: { type: :string },
|
|
trust_level: { type: :string },
|
|
suspected: { type: :boolean },
|
|
banned: { type: :boolean },
|
|
created_at: { type: :string, format: :date_time },
|
|
updated_at: { type: :string, format: :date_time },
|
|
last_heartbeat_at: { type: :number, nullable: true },
|
|
email_addresses: { type: :array, items: { type: :string } },
|
|
api_keys_count: { type: :integer },
|
|
stats: {
|
|
type: :object,
|
|
properties: {
|
|
total_heartbeats: { type: :integer },
|
|
total_coding_time: { type: :number },
|
|
languages_used: { type: :integer },
|
|
projects_worked_on: { type: :integer },
|
|
days_active: { type: :integer }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/heartbeats' do
|
|
get('Get admin user heartbeats') do
|
|
tags 'Admin Utils'
|
|
description 'Get heartbeats for a user (Admin view).'
|
|
security [ AdminToken: [] ]
|
|
produces 'application/json'
|
|
|
|
parameter name: :user_id, in: :query, type: :string, description: 'User ID'
|
|
parameter name: :start_date, in: :query, type: :string, description: 'Start date (YYYY-MM-DD or timestamp)'
|
|
parameter name: :end_date, in: :query, type: :string, description: 'End date (YYYY-MM-DD or timestamp)'
|
|
parameter name: :project, in: :query, type: :string, description: 'Project name'
|
|
parameter name: :language, in: :query, type: :string, description: 'Language'
|
|
parameter name: :entity, in: :query, type: :string, description: 'Entity (file path or app name)'
|
|
parameter name: :editor, in: :query, type: :string, description: 'Editor'
|
|
parameter name: :machine, in: :query, type: :string, description: 'Machine'
|
|
parameter name: :limit, in: :query, type: :integer, description: 'Limit'
|
|
parameter name: :offset, in: :query, type: :integer, description: 'Offset'
|
|
|
|
response(200, 'successful') do
|
|
schema type: :object,
|
|
properties: {
|
|
user_id: { type: :integer },
|
|
heartbeats: {
|
|
type: :array,
|
|
items: {
|
|
type: :object,
|
|
properties: {
|
|
id: { type: :integer },
|
|
time: { type: :number },
|
|
lineno: { type: :integer, nullable: true },
|
|
cursorpos: { type: :integer, nullable: true },
|
|
is_write: { type: :boolean, nullable: true },
|
|
project: { type: :string, nullable: true },
|
|
language: { type: :string, nullable: true },
|
|
entity: { type: :string, nullable: true },
|
|
branch: { type: :string, nullable: true },
|
|
category: { type: :string, nullable: true },
|
|
editor: { type: :string, nullable: true },
|
|
machine: { type: :string, nullable: true },
|
|
user_agent: { type: :string, nullable: true },
|
|
ip_address: { type: :string, nullable: true },
|
|
lines: { type: :integer, nullable: true },
|
|
source_type: { type: :string, nullable: true }
|
|
}
|
|
}
|
|
},
|
|
total_count: { type: :integer },
|
|
has_more: { type: :boolean }
|
|
}
|
|
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user) do
|
|
u = User.create!(username: 'hb_user')
|
|
EmailAddress.create!(user: u, email: 'hb@example.com')
|
|
u
|
|
end
|
|
let(:user_id) { user.id }
|
|
let(:start_date) { nil }
|
|
let(:end_date) { nil }
|
|
let(:project) { nil }
|
|
let(:language) { nil }
|
|
let(:entity) { nil }
|
|
let(:editor) { nil }
|
|
let(:machine) { nil }
|
|
let(:limit) { 10 }
|
|
let(:offset) { 0 }
|
|
run_test!
|
|
end
|
|
|
|
response(404, 'user not found') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user_id) { '0' }
|
|
let(:start_date) { nil }
|
|
let(:end_date) { nil }
|
|
let(:project) { nil }
|
|
let(:language) { nil }
|
|
let(:entity) { nil }
|
|
let(:editor) { nil }
|
|
let(:machine) { nil }
|
|
let(:limit) { 10 }
|
|
let(:offset) { 0 }
|
|
run_test!
|
|
end
|
|
|
|
response(422, 'invalid date filter') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user) do
|
|
u = User.create!(username: 'hb_user_invalid_date')
|
|
EmailAddress.create!(user: u, email: 'hb-invalid@example.com')
|
|
u
|
|
end
|
|
let(:user_id) { user.id }
|
|
let(:start_date) { 'not-a-date' }
|
|
let(:end_date) { nil }
|
|
let(:project) { nil }
|
|
let(:language) { nil }
|
|
let(:entity) { nil }
|
|
let(:editor) { nil }
|
|
let(:machine) { nil }
|
|
let(:limit) { 10 }
|
|
let(:offset) { 0 }
|
|
schema '$ref' => '#/components/schemas/Error'
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/heartbeat_values' do
|
|
get('Get heartbeat values') do
|
|
tags 'Admin Utils'
|
|
description 'Get specific values from heartbeats.'
|
|
security [ AdminToken: [] ]
|
|
produces 'application/json'
|
|
|
|
parameter name: :user_id, in: :query, type: :string, description: 'User ID'
|
|
parameter name: :field, in: :query, type: :string, description: 'Field to retrieve (projects, languages, etc.)'
|
|
parameter name: :start_date, in: :query, type: :string, description: 'Start date (YYYY-MM-DD or timestamp)'
|
|
parameter name: :end_date, in: :query, type: :string, description: 'End date (YYYY-MM-DD or timestamp)'
|
|
parameter name: :limit, in: :query, type: :integer, description: 'Limit results'
|
|
|
|
response(200, 'successful') do
|
|
schema type: :object,
|
|
properties: {
|
|
user_id: { type: :integer },
|
|
field: { type: :string },
|
|
values: { type: :array, items: { type: :string } },
|
|
count: { type: :integer }
|
|
}
|
|
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user) do
|
|
u = User.create!(username: 'projects_user')
|
|
EmailAddress.create!(user: u, email: 'projects@example.com')
|
|
u
|
|
end
|
|
let(:user_id) { user.id }
|
|
let(:field) { 'projects' }
|
|
let(:start_date) { nil }
|
|
let(:end_date) { nil }
|
|
let(:limit) { 5000 }
|
|
run_test!
|
|
end
|
|
|
|
response(404, 'user not found') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user_id) { '0' }
|
|
let(:field) { 'projects' }
|
|
let(:start_date) { nil }
|
|
let(:end_date) { nil }
|
|
let(:limit) { 5000 }
|
|
run_test!
|
|
end
|
|
|
|
response(422, 'invalid date filter') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user) do
|
|
u = User.create!(username: 'projects_invalid')
|
|
EmailAddress.create!(user: u, email: 'projects-invalid@example.com')
|
|
u
|
|
end
|
|
let(:user_id) { user.id }
|
|
let(:field) { 'projects' }
|
|
let(:start_date) { 'not-a-date' }
|
|
let(:end_date) { nil }
|
|
let(:limit) { 5000 }
|
|
schema '$ref' => '#/components/schemas/Error'
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/get_users_by_ip' do
|
|
get('Get users by IP') do
|
|
tags 'Admin Utils'
|
|
description 'Find users associated with an IP address.'
|
|
security [ AdminToken: [] ]
|
|
produces 'application/json'
|
|
|
|
parameter name: :ip, in: :query, type: :string, description: 'IP Address'
|
|
|
|
response(200, 'successful') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:ip) { '127.0.0.1' }
|
|
schema type: :object,
|
|
properties: {
|
|
users: {
|
|
type: :array,
|
|
items: {
|
|
type: :object,
|
|
properties: {
|
|
user_id: { type: :integer },
|
|
ip_address: { type: :string },
|
|
machine: { type: :string, nullable: true },
|
|
user_agent: { type: :string, nullable: true }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/get_users_by_machine' do
|
|
get('Get users by machine') do
|
|
tags 'Admin Utils'
|
|
description 'Find users associated with a machine ID.'
|
|
security [ AdminToken: [] ]
|
|
produces 'application/json'
|
|
|
|
parameter name: :machine, in: :query, type: :string, description: 'Machine ID'
|
|
|
|
response(200, 'successful') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:machine) { 'some-machine-id' }
|
|
schema type: :object,
|
|
properties: {
|
|
users: {
|
|
type: :array,
|
|
items: {
|
|
type: :object,
|
|
properties: {
|
|
user_id: { type: :integer },
|
|
machine: { type: :string }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/stats' do
|
|
get('Get admin user stats') do
|
|
tags 'Admin Utils'
|
|
description 'Get detailed stats for a user (Admin view).'
|
|
security [ AdminToken: [] ]
|
|
produces 'application/json'
|
|
|
|
parameter name: :user_id, in: :query, type: :string, description: 'User ID'
|
|
|
|
response(200, 'successful') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user) do
|
|
u = User.create!(username: 'stats_user')
|
|
EmailAddress.create!(user: u, email: 'stats@example.com')
|
|
u
|
|
end
|
|
let(:user_id) { user.id }
|
|
schema type: :object,
|
|
properties: {
|
|
user_id: { type: :integer },
|
|
username: { type: :string },
|
|
date: { type: :string, format: :date_time },
|
|
timezone: { type: :string, nullable: true },
|
|
total_heartbeats: { type: :integer },
|
|
total_duration: { type: :number },
|
|
heartbeats: {
|
|
type: :array,
|
|
items: {
|
|
type: :object,
|
|
properties: {
|
|
id: { type: :integer },
|
|
time: { type: :string },
|
|
created_at: { type: :string, format: :date_time },
|
|
project: { type: :string, nullable: true },
|
|
branch: { type: :string, nullable: true },
|
|
category: { type: :string, nullable: true },
|
|
dependencies: { type: :string, nullable: true },
|
|
editor: { type: :string, nullable: true },
|
|
entity: { type: :string, nullable: true },
|
|
language: { type: :string, nullable: true },
|
|
machine: { type: :string, nullable: true },
|
|
operating_system: { type: :string, nullable: true },
|
|
type: { type: :string, nullable: true },
|
|
user_agent: { type: :string, nullable: true },
|
|
line_additions: { type: :integer, nullable: true },
|
|
line_deletions: { type: :integer, nullable: true },
|
|
lineno: { type: :integer, nullable: true },
|
|
lines: { type: :integer, nullable: true },
|
|
cursorpos: { type: :integer, nullable: true },
|
|
project_root_count: { type: :integer, nullable: true },
|
|
is_write: { type: :boolean, nullable: true },
|
|
source_type: { type: :string, nullable: true },
|
|
ysws_program: { type: :string, nullable: true },
|
|
ip_address: { type: :string, nullable: true }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
run_test!
|
|
end
|
|
|
|
response(404, 'user not found') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user_id) { '0' }
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/projects' do
|
|
get('Get admin user projects') do
|
|
tags 'Admin Utils'
|
|
description 'Get projects for a user (Admin view).'
|
|
security [ AdminToken: [] ]
|
|
produces 'application/json'
|
|
|
|
parameter name: :user_id, in: :query, type: :string, description: 'User ID'
|
|
|
|
response(200, 'successful') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user) do
|
|
u = User.create!(username: 'hb_values_user')
|
|
EmailAddress.create!(user: u, email: 'hb_vals@example.com')
|
|
u
|
|
end
|
|
let(:user_id) { user.id }
|
|
let(:field) { 'projects' }
|
|
schema type: :object,
|
|
properties: {
|
|
user_id: { type: :integer },
|
|
username: { type: :string },
|
|
total_projects: { type: :integer },
|
|
projects: {
|
|
type: :array,
|
|
items: {
|
|
type: :object,
|
|
properties: {
|
|
name: { type: :string, nullable: true },
|
|
total_heartbeats: { type: :integer },
|
|
total_duration: { type: :number },
|
|
first_heartbeat: { type: :number, nullable: true },
|
|
last_heartbeat: { type: :number, nullable: true },
|
|
languages: { type: :array, items: { type: :string } },
|
|
repo: { type: :string, nullable: true },
|
|
repo_mapping_id: { type: :integer, nullable: true },
|
|
archived: { type: :boolean }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
run_test!
|
|
end
|
|
|
|
response(404, 'user not found') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user_id) { '0' }
|
|
let(:field) { 'projects' }
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/trust_logs' do
|
|
get('Get user trust logs') do
|
|
tags 'Admin Utils'
|
|
description 'Get trust level audit logs for a user.'
|
|
security [ AdminToken: [] ]
|
|
produces 'application/json'
|
|
|
|
parameter name: :user_id, in: :query, type: :string, description: 'User ID'
|
|
|
|
response(200, 'successful') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user_id) { '1' }
|
|
schema type: :object,
|
|
properties: {
|
|
trust_logs: {
|
|
type: :array,
|
|
items: {
|
|
type: :object,
|
|
properties: {
|
|
id: { type: :integer },
|
|
previous_trust_level: { type: :string, nullable: true },
|
|
new_trust_level: { type: :string },
|
|
reason: { type: :string, nullable: true },
|
|
notes: { type: :string, nullable: true },
|
|
created_at: { type: :string, format: :date_time },
|
|
changed_by: {
|
|
type: :object,
|
|
properties: {
|
|
id: { type: :integer },
|
|
username: { type: :string },
|
|
display_name: { type: :string },
|
|
admin_level: { type: :string }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/get_user_by_email' do
|
|
post('Get user by email') do
|
|
tags 'Admin Utils'
|
|
description 'Lookup user by email (POST).'
|
|
security [ AdminToken: [] ]
|
|
consumes 'application/json'
|
|
produces 'application/json'
|
|
|
|
parameter name: :payload, in: :body, schema: {
|
|
type: :object,
|
|
properties: {
|
|
email: { type: :string }
|
|
}
|
|
}
|
|
|
|
response(200, 'successful') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:payload) { { email: 'test@example.com' } }
|
|
schema type: :object,
|
|
properties: {
|
|
user_id: { type: :integer }
|
|
}
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/search_fuzzy' do
|
|
post('Fuzzy search users') do
|
|
tags 'Admin Utils'
|
|
description 'Search users by fuzzy matching.'
|
|
security [ AdminToken: [] ]
|
|
consumes 'application/json'
|
|
produces 'application/json'
|
|
|
|
parameter name: :payload, in: :body, schema: {
|
|
type: :object,
|
|
properties: {
|
|
query: { type: :string }
|
|
}
|
|
}
|
|
|
|
response(200, 'successful') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:payload) { { query: 'test' } }
|
|
schema type: :object,
|
|
properties: {
|
|
users: {
|
|
type: :array,
|
|
items: {
|
|
type: :object,
|
|
properties: {
|
|
id: { type: :integer },
|
|
username: { type: :string },
|
|
slack_username: { type: :string, nullable: true },
|
|
github_username: { type: :string, nullable: true },
|
|
slack_avatar_url: { type: :string, nullable: true },
|
|
github_avatar_url: { type: :string, nullable: true },
|
|
email: { type: :string },
|
|
rank_score: { type: :number }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
|
|
path '/api/admin/v1/user/convict' do
|
|
post('Convict user') do
|
|
tags 'Admin Utils'
|
|
description 'Mark a user as convicted/banned.'
|
|
security [ AdminToken: [] ]
|
|
consumes 'application/json'
|
|
produces 'application/json'
|
|
|
|
parameter name: :payload, in: :body, schema: {
|
|
type: :object,
|
|
properties: {
|
|
user_id: { type: :integer },
|
|
reason: { type: :string }
|
|
}
|
|
}
|
|
|
|
response(200, 'successful') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:user) do
|
|
u = User.create!(username: 'convict_me')
|
|
EmailAddress.create!(user: u, email: 'convict@example.com')
|
|
u
|
|
end
|
|
let(:payload) { { user_id: user.id, reason: 'spam', trust_level: 'red' } }
|
|
schema type: :object,
|
|
properties: {
|
|
success: { type: :boolean },
|
|
message: { type: :string },
|
|
user: {
|
|
type: :object,
|
|
properties: {
|
|
id: { type: :integer },
|
|
username: { type: :string },
|
|
trust_level: { type: :string },
|
|
updated_at: { type: :string, format: :date_time }
|
|
}
|
|
},
|
|
audit_log: {
|
|
type: :object,
|
|
properties: {
|
|
changed_by: { type: :string },
|
|
reason: { type: :string },
|
|
notes: { type: :string, nullable: true },
|
|
timestamp: { type: :string, format: :date_time }
|
|
}
|
|
}
|
|
}
|
|
run_test!
|
|
end
|
|
|
|
response(404, 'user not found') do
|
|
let(:Authorization) { "Bearer dev-admin-api-key-12345" }
|
|
let(:payload) { { user_id: 0, reason: 'spam', trust_level: 'red' } }
|
|
run_test!
|
|
end
|
|
end
|
|
end
|
|
end
|