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

API admin/users, bugfix page/total pages #1001

Open
wants to merge 52 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
95deb6a
add gem, basic setup
yksflip Nov 7, 2022
df3a2c0
add authorization to tests
yksflip Nov 7, 2022
dbab0ef
refactor invalid token, scope
yksflip Nov 7, 2022
f599578
remove apivore
yksflip Nov 7, 2022
614aef7
add schemas
yksflip Nov 21, 2022
78bb7c6
remove old api tests
yksflip Nov 21, 2022
b35f33a
fix style validations
yksflip Nov 21, 2022
a8698d3
restore hashie gem
yksflip Nov 21, 2022
e8303a8
add config_spec
yksflip Nov 21, 2022
71ae705
add navigation_spec
yksflip Nov 21, 2022
1020035
rename tests according to api controllers
yksflip Nov 21, 2022
3b7eae6
wip: article_categories spec
yksflip Nov 21, 2022
102e0e7
wip swagger spec article_categories
Viehlieb Nov 25, 2022
c6dd8a1
rswag financial_transaction_class
Viehlieb Nov 25, 2022
305d105
wip rswagging
Viehlieb Nov 28, 2022
ecf5c6e
rswagged financial_transactions
Viehlieb Nov 29, 2022
d8b2aa0
wip user/financial_transactions - first api post test
Viehlieb Nov 29, 2022
92e8a06
add order_articles_spec
yksflip Nov 28, 2022
3c00461
fix swagger violations
yksflip Dec 1, 2022
ab26520
user/group_order_articles rswagged - wipfinancial_transactions
Viehlieb Dec 2, 2022
be4f4d6
add orders spec
yksflip Dec 1, 2022
af6e06d
page/per_pagefor each controller, some summaries/descriptions updated
Viehlieb Dec 5, 2022
ccff79b
fix: article categories and 404 helper
yksflip Dec 12, 2022
fc9637f
refactor: financial transaction classes
yksflip Dec 12, 2022
3222e79
refactor: nullable values, financial transaction types
yksflip Dec 12, 2022
6bacbe9
fix: config
yksflip Dec 12, 2022
1c5a3c6
fix: financial category tag
yksflip Dec 12, 2022
a32bc88
refactor: financial transaction spec
yksflip Dec 12, 2022
e41c6e5
refactor: financial transaction spec
yksflip Dec 12, 2022
57593db
refactor: order articles spec
yksflip Dec 12, 2022
4c0a7ae
refactor: extract id parameter
yksflip Dec 12, 2022
edd6e24
refactor: id in helper functions actually not needed
yksflip Dec 12, 2022
482752f
refactor: meta oneline
yksflip Dec 12, 2022
64e5908
fix: financial transaction amount float not int
yksflip Dec 12, 2022
31a419c
fix: order article response body
yksflip Dec 12, 2022
3765042
fix: GroupOrderArticle Schema
yksflip Dec 12, 2022
eac550d
refactor: group order articles
yksflip Dec 12, 2022
5201d17
refactor: q ordered article parameter
yksflip Dec 12, 2022
e4d0222
refactor: cleanup group order articles
yksflip Dec 14, 2022
c6c5daa
fix: rubocop RSpec/EmptyExampleGroup
yksflip Jan 2, 2023
a4a3416
fix: rubocop RSpec/VariableName snake_case for Authorization header
yksflip Jan 2, 2023
f8c9aaf
fix: rubocop Metrics/BlockLength for config/routes
yksflip Jan 2, 2023
1835848
refactor: pagination param
yksflip Jan 2, 2023
619fdbe
fix: minor foo
yksflip Jan 2, 2023
138b99e
fix: missed pagination refactoring
yksflip Jan 2, 2023
a3452e9
fix: quotes
yksflip Jan 2, 2023
caef784
fix: fix rsawg for rails upgrade
yksflip Jan 16, 2023
78886d9
remove old api tests
yksflip Jan 16, 2023
cc22969
First successfull steps in admin/users
SomeMichael Apr 13, 2023
74e5969
Merge branch '1_API_extension_based_on_y28' of https://github.com/Som…
SomeMichael Apr 25, 2023
f4de70d
bugfix: correct output of page and total count
SomeMichael May 10, 2023
b4348ff
Exending api by admin/users scope
SomeMichael May 10, 2023
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
28 changes: 27 additions & 1 deletion .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ Metrics/AbcSize:
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, AllowedMethods, AllowedPatterns, IgnoredMethods, inherit_mode.
# AllowedMethods: refine
Metrics/BlockLength:
Max: 210
Max: 212

# Offense count: 6
# Configuration parameters: CountBlocks.
Expand Down Expand Up @@ -451,6 +451,24 @@ RSpec/DescribedClass:
- "spec/models/ordergroup_spec.rb"
- "spec/models/user_spec.rb"

# Offense count: 15
# This cop supports unsafe autocorrection (--autocorrect-all).
RSpec/EmptyExampleGroup:
Exclude:
- 'spec/requests/api/article_categories_spec.rb'
- 'spec/requests/api/configs_spec.rb'
- 'spec/requests/api/financial_transaction_classes_spec.rb'
- 'spec/requests/api/financial_transaction_types_spec.rb'
- 'spec/requests/api/financial_transactions_spec.rb'
- 'spec/requests/api/navigations_spec.rb'
- 'spec/requests/api/order_articles_spec.rb'
- 'spec/requests/api/orders_spec.rb'
- 'spec/requests/api/user/financial_transactions_spec.rb'
- 'spec/requests/api/user/group_order_articles_spec.rb'
- 'spec/requests/api/user/users_spec.rb'



# Offense count: 65
# Configuration parameters: CountAsOne.
RSpec/ExampleLength:
Expand Down Expand Up @@ -581,6 +599,14 @@ RSpec/ScatteredSetup:
- "spec/integration/balancing_spec.rb"
- "spec/integration/login_spec.rb"

# Offense count: 4
# Configuration parameters: AllowedPatterns, IgnoredPatterns.
# SupportedStyles: snake_case, camelCase
RSpec/VariableName:
EnforcedStyle: snake_case
AllowedPatterns:
- ^Authorization$

# Offense count: 1
# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
RSpec/VerifiedDoubles:
Expand Down
6 changes: 4 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ gem 'gaffe'
gem 'ruby-filemagic'
gem 'mime-types'
gem 'midi-smtp-server'
gem 'hashie', '~> 3.4.6', require: false # https://github.com/westfieldlabs/apivore/issues/114
gem 'rswag-api'
gem 'rswag-ui'

# we use the git version of acts_as_versioned, and need to include it in this Gemfile
gem 'acts_as_versioned', git: 'https://github.com/technoweenie/acts_as_versioned.git'
Expand Down Expand Up @@ -116,6 +119,5 @@ group :test do
gem 'simplecov', require: false
gem 'simplecov-lcov', require: false
# api
gem 'apivore', require: false
gem 'hashie', '~> 3.4.6', require: false # https://github.com/westfieldlabs/apivore/issues/114
gem 'rswag-specs'
end
21 changes: 13 additions & 8 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,6 @@ GEM
activerecord (>= 3.0.0)
addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0)
apivore (1.6.2)
actionpack (>= 4, < 6)
hashie (~> 3.3)
json-schema (~> 2.5)
rspec (~> 3)
rspec-expectations (~> 3.1)
rspec-mocks (~> 3.1)
apparition (0.6.0)
capybara (~> 3.13, < 4)
websocket-driver (>= 0.6.5)
Expand Down Expand Up @@ -430,6 +423,16 @@ GEM
rspec-rerun (1.1.0)
rspec (~> 3.0)
rspec-support (3.11.1)
rswag-api (2.7.0)
railties (>= 3.1, < 7.1)
rswag-specs (2.7.0)
activesupport (>= 3.1, < 7.1)
json-schema (>= 2.2, < 4.0)
railties (>= 3.1, < 7.1)
rspec-core (>= 2.14)
rswag-ui (2.7.0)
actionpack (>= 3.1, < 7.1)
railties (>= 3.1, < 7.1)
rubocop (1.36.0)
json (~> 2.3)
parallel (~> 1.10)
Expand Down Expand Up @@ -557,7 +560,6 @@ DEPENDENCIES
active_model_serializers (~> 0.10.0)
acts_as_tree
acts_as_versioned!
apivore
apparition
attribute_normalizer
better_errors
Expand Down Expand Up @@ -617,6 +619,9 @@ DEPENDENCIES
rspec-core
rspec-rails
rspec-rerun
rswag-api
rswag-specs
rswag-ui
rubocop
rubocop-rails
rubocop-rspec
Expand Down
142 changes: 142 additions & 0 deletions app/controllers/api/v1/admin/users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
class Api::V1::Admin::UsersController < Api::V1::BaseController
include Concerns::CollectionScope

before_action -> { doorkeeper_authorize! 'user:read', 'user:write' }

def index
render json: search_scope, each_serializer: UserAlldataSerializer, meta: collection_meta(search_scope)
end

def show
@users_scope = :all
@user = find_user_by_id
render_data
end

def create
check_params
@user = User.new(params[:user])
save_render
end

def update
check_params
@user = find_user_by_id
@user.update(params[:user])
save_render
end

def destroy
@user = find_user_by_id
@user.mark_as_deleted
render_data
rescue => @error
raise ActiveRecord::RecordInvalid, t('admin.users.destroy.error', error: @error.message)
end

def restore
@users_scope = :deleted
@user = find_user_by_id
@user.restore
render_data
rescue => @error
raise ActiveRecord::RecordInvalid, t('admin.users.restore.error', error: @error.message)
end

private

def render_response
if @error.nil?
render_data
else
raise ActiveRecord::RecordNotSaved, @message
end
end

def save_render
if @user.save
render_data
else
raise ActiveRecord::RecordNotSaved, @user.errors.messages
end
rescue => error
raise ActiveRecord::RecordNotSaved, error.message
end

def render_data
data = {}
# Any better way to achieve this? Nested serializers don't seam to be possible..?
data[:user] = {
id: @user.id,
first_name: @user.first_name,
last_name: @user.last_name,
email: @user.email,
phone: @user.phone,
settings_attributes: {
profile: @user.settings[:profile],
notify: @user.settings[:notify],
messages: @user.settings[:messages]
}
}
data[:user][:ordergroupid] = @user.ordergroup ? @user.ordergroup.id : nil
if @user.deleted_at
data[:user][:deleted_at] = @user.deleted_at
end
render status: :ok, json: data
end

def check_params
# we do this for checking settings attributes. Any better way? Better in model?
# note: this is NOT checked anywhere else!!!???
if params[:user].key?(:settings_attributes)
params[:user][:settings_attributes].each do |k1, v1|
unless %w[profile notify].include?(k1)
raise ActiveRecord::RecordNotSaved, param_not_allowed_message(k1, 'settings_attributes')
end

v1.each do |k2, v2|
case k1
when "profile"
unless %w[language phone_is_public email_is_public].include?(k2)
raise ActiveRecord::RecordNotSaved, param_not_allowed_message(k2, k1)
end
when "notify"
unless %w[order_finished order_received negative_balance upcoming_tasks].include?(k2)
raise ActiveRecord::RecordNotSaved, param_not_allowed_message(k2, k1)
end
end

unless [true, false, '0', '1', 0, 1].include?(v2)
raise ActiveRecord::RecordNotSaved, param_not_allowed_message(v2, k2)
end

case v2
when "1", 1
params[:user][:settings_attributes][k1][k2] = true
when "0", 0
params[:user][:settings_attributes][k1][k2] = false
end
end
end
end
end

def param_not_allowed_message(a, b)
# translate it?
"'#{a}' not allowed in '#{b}'"
end

def find_user_by_id
scope.find(params.require(:id))
end

def scope
if (@users_scope == :deleted) || params[:show_deleted]
User.deleted
elsif @users_scope == :all
User
else
User.undeleted
end
end
end
19 changes: 16 additions & 3 deletions app/controllers/concerns/collection_scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,22 @@ def default_per_page
20
end

def default_page
1
end

def max_per_page
250
end

def page
if params[:page]
params[:page].to_i
else
default_page
end
end

def per_page
# allow max_per_page and default_per_page to be nil as well
if params[:per_page]
Expand All @@ -27,21 +39,22 @@ def per_page
def search_scope
s = scope
s = s.ransack(params[:q], auth_object: ransack_auth_object).result(distinct: true) if params[:q]
s = s.page(params[:page].to_i).per(per_page) if per_page && per_page >= 0
s = s.page(page).per(per_page) if per_page && per_page >= 0
s
end

def render_collection(scope)
render json: scope, meta: collection_meta(scope)
end

# to_f required, otherwise result of (scope.total_count.to_f / [1, per_page].max) is integer
def collection_meta(scope, extra = {})
return unless scope.respond_to?(:total_count) && per_page

{
page: params[:page].to_i,
page: page,
per_page: per_page,
total_pages: (scope.total_count / [1, per_page].max).ceil,
total_pages: (scope.total_count.to_f / [1, per_page].max).ceil,
total_count: scope.total_count
}.merge(extra)
end
Expand Down
53 changes: 49 additions & 4 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,66 @@ def ordergroup
validates_format_of :iban, :with => /\A[A-Z]{2}[0-9]{2}[0-9A-Z]{,30}\z/, :allow_blank => true
validates_uniqueness_of :iban, :case_sensitive => false, :allow_blank => true

before_validation :set_password
# Fully initializing all settings further below. But there is an issue with an clean database (db:reset)
# for Anton Administrator (missing locale)
after_initialize do
settings.defaults['profile'] = { 'language' => I18n.default_locale } unless settings.profile
settings.defaults['messages'] = { 'send_as_email' => true } unless settings.messages
settings.defaults['notify'] = { 'upcoming_tasks' => true } unless settings.notify
settings.defaults['profile'] = { 'language' => I18n.default_locale } unless settings.profile
# settings.defaults['messages'] = { 'send_as_email' => true } unless settings.messages
# settings.defaults['notify'] = { 'upcoming_tasks' => true } unless settings.notify
end

after_initialize do
# fully initialize user settings
# settings.defaults['profile'] = {
# 'language' => I18n.default_locale,
# 'phone_is_public' => false,
# 'email_is_public' => false
# } unless settings['profile']

# settings.defaults['messages'] = {
# 'send_as_email' => true
# } unless settings['messages']

# settings.defaults['notify'] = {
# 'order_finished' => false,
# 'order_received' => false,
# 'upcoming_tasks' => true,
# 'negative_balance' => false
# } unless settings['notify']
end

before_validation :set_password

before_save do
if send_welcome_mail?
self.reset_password_token = new_random_password(16)
self.reset_password_expires = Time.now.advance(days: 2)
end
end

# While debugging it was found that after save is also triggered in user/index calls.
# Is that a wanted behavior?
after_save do
# We fully initialize settings here in order to keep them optional in api
# If we don't do that then, in case of missing settings or settings which are equal
# to the default values, no settings were saved in the former approach
self.settings['profile'] = {
'language' => I18n.default_locale,
'phone_is_public' => false,
'email_is_public' => false
} unless self.settings['profile']

self.settings['messages'] = {
'send_as_email' => true
} unless self.settings['messages']

self.settings['notify'] = {
'order_finished' => false,
'order_received' => false,
'upcoming_tasks' => true,
'negative_balance' => false
} unless self.settings['notify']

settings_attributes.each do |key, value|
value.each do |k, v|
case v
Expand Down
10 changes: 10 additions & 0 deletions app/serializers/user_alldata_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class UserAlldataSerializer < ActiveModel::Serializer
attributes :id, :first_name, :last_name, :email, :locale, :phone, :ordergroupid
# conditional!
# https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/general/serializers.md#attribute
attribute :deleted_at, unless: -> { object.deleted_at.nil? }

def ordergroupid
object.ordergroup ? object.ordergroup.id : nil
end
end
Loading