feat: Ability to delete account for administrators (#1874)
## Description Add account delete option in the user account settings. Fixes #1555 ## Type of change - [ ] New feature (non-breaking change which adds functionality)   ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Sojan Jose <sojan@pepalo.com> Co-authored-by: Sojan Jose <sojan.official@gmail.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -1,130 +1,14 @@
|
||||
module Enterprise::Account
|
||||
CAPTAIN_RESPONSES = 'captain_responses'.freeze
|
||||
CAPTAIN_DOCUMENTS = 'captain_documents'.freeze
|
||||
CAPTAIN_RESPONSES_USAGE = 'captain_responses_usage'.freeze
|
||||
CAPTAIN_DOCUMENTS_USAGE = 'captain_documents_usage'.freeze
|
||||
def mark_for_deletion(reason = 'manual_deletion')
|
||||
result = custom_attributes.merge!('marked_for_deletion_at' => 7.days.from_now.iso8601, 'marked_for_deletion_reason' => reason) && save
|
||||
|
||||
def usage_limits
|
||||
{
|
||||
agents: agent_limits.to_i,
|
||||
inboxes: get_limits(:inboxes).to_i,
|
||||
captain: {
|
||||
documents: get_captain_limits(:documents),
|
||||
responses: get_captain_limits(:responses)
|
||||
}
|
||||
}
|
||||
# Send notification to admin users if the account was successfully marked for deletion
|
||||
AdministratorNotifications::AccountNotificationMailer.with(account: self).account_deletion(self, reason).deliver_later if result
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def increment_response_usage
|
||||
current_usage = custom_attributes[CAPTAIN_RESPONSES_USAGE].to_i || 0
|
||||
custom_attributes[CAPTAIN_RESPONSES_USAGE] = current_usage + 1
|
||||
save
|
||||
end
|
||||
|
||||
def reset_response_usage
|
||||
custom_attributes[CAPTAIN_RESPONSES_USAGE] = 0
|
||||
save
|
||||
end
|
||||
|
||||
def update_document_usage
|
||||
# this will ensure that the document count is always accurate
|
||||
custom_attributes[CAPTAIN_DOCUMENTS_USAGE] = captain_documents.count
|
||||
save
|
||||
end
|
||||
|
||||
def subscribed_features
|
||||
plan_features = InstallationConfig.find_by(name: 'CHATWOOT_CLOUD_PLAN_FEATURES')&.value
|
||||
return [] if plan_features.blank?
|
||||
|
||||
plan_features[plan_name]
|
||||
end
|
||||
|
||||
def captain_monthly_limit
|
||||
default_limits = default_captain_limits
|
||||
|
||||
{
|
||||
documents: self[:limits][CAPTAIN_DOCUMENTS] || default_limits['documents'],
|
||||
responses: self[:limits][CAPTAIN_RESPONSES] || default_limits['responses']
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_captain_limits(type)
|
||||
total_count = captain_monthly_limit[type.to_s].to_i
|
||||
|
||||
consumed = if type == :documents
|
||||
custom_attributes[CAPTAIN_DOCUMENTS_USAGE].to_i || 0
|
||||
else
|
||||
custom_attributes[CAPTAIN_RESPONSES_USAGE].to_i || 0
|
||||
end
|
||||
|
||||
consumed = 0 if consumed.negative?
|
||||
|
||||
{
|
||||
total_count: total_count,
|
||||
current_available: (total_count - consumed).clamp(0, total_count),
|
||||
consumed: consumed
|
||||
}
|
||||
end
|
||||
|
||||
def default_captain_limits
|
||||
max_limits = { documents: ChatwootApp.max_limit, responses: ChatwootApp.max_limit }.with_indifferent_access
|
||||
zero_limits = { documents: 0, responses: 0 }.with_indifferent_access
|
||||
plan_quota = InstallationConfig.find_by(name: 'CAPTAIN_CLOUD_PLAN_LIMITS')&.value
|
||||
|
||||
# If there are no limits configured, we allow max usage
|
||||
return max_limits if plan_quota.blank?
|
||||
|
||||
# if there is plan_quota configred, but plan_name is not present, we return zero limits
|
||||
return zero_limits if plan_name.blank?
|
||||
|
||||
begin
|
||||
# Now we parse the plan_quota and return the limits for the plan name
|
||||
# but if there's no plan_name present in the plan_quota, we return zero limits
|
||||
plan_quota = JSON.parse(plan_quota) if plan_quota.present?
|
||||
plan_quota[plan_name.downcase] || zero_limits
|
||||
rescue StandardError
|
||||
# if there's any error in parsing the plan_quota, we return max limits
|
||||
# this is to ensure that we don't block the user from using the product
|
||||
max_limits
|
||||
end
|
||||
end
|
||||
|
||||
def plan_name
|
||||
custom_attributes['plan_name']
|
||||
end
|
||||
|
||||
def agent_limits
|
||||
subscribed_quantity = custom_attributes['subscribed_quantity']
|
||||
subscribed_quantity || get_limits(:agents)
|
||||
end
|
||||
|
||||
def get_limits(limit_name)
|
||||
config_name = "ACCOUNT_#{limit_name.to_s.upcase}_LIMIT"
|
||||
return self[:limits][limit_name.to_s] if self[:limits][limit_name.to_s].present?
|
||||
|
||||
return GlobalConfig.get(config_name)[config_name] if GlobalConfig.get(config_name)[config_name].present?
|
||||
|
||||
ChatwootApp.max_limit
|
||||
end
|
||||
|
||||
def validate_limit_keys
|
||||
errors.add(:limits, ': Invalid data') unless self[:limits].is_a? Hash
|
||||
self[:limits] = {} if self[:limits].blank?
|
||||
|
||||
limit_schema = {
|
||||
'type' => 'object',
|
||||
'properties' => {
|
||||
'inboxes' => { 'type': 'number' },
|
||||
'agents' => { 'type': 'number' },
|
||||
'captain_responses' => { 'type': 'number' },
|
||||
'captain_documents' => { 'type': 'number' }
|
||||
},
|
||||
'required' => [],
|
||||
'additionalProperties' => false
|
||||
}
|
||||
|
||||
errors.add(:limits, ': Invalid data') unless JSONSchemer.schema(limit_schema).valid?(self[:limits])
|
||||
def unmark_for_deletion
|
||||
custom_attributes.delete('marked_for_deletion_at') && custom_attributes.delete('marked_for_deletion_reason') && save
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
module Enterprise::Account::PlanUsageAndLimits
|
||||
CAPTAIN_RESPONSES = 'captain_responses'.freeze
|
||||
CAPTAIN_DOCUMENTS = 'captain_documents'.freeze
|
||||
CAPTAIN_RESPONSES_USAGE = 'captain_responses_usage'.freeze
|
||||
CAPTAIN_DOCUMENTS_USAGE = 'captain_documents_usage'.freeze
|
||||
|
||||
def usage_limits
|
||||
{
|
||||
agents: agent_limits.to_i,
|
||||
inboxes: get_limits(:inboxes).to_i,
|
||||
captain: {
|
||||
documents: get_captain_limits(:documents),
|
||||
responses: get_captain_limits(:responses)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def increment_response_usage
|
||||
current_usage = custom_attributes[CAPTAIN_RESPONSES_USAGE].to_i || 0
|
||||
custom_attributes[CAPTAIN_RESPONSES_USAGE] = current_usage + 1
|
||||
save
|
||||
end
|
||||
|
||||
def reset_response_usage
|
||||
custom_attributes[CAPTAIN_RESPONSES_USAGE] = 0
|
||||
save
|
||||
end
|
||||
|
||||
def update_document_usage
|
||||
# this will ensure that the document count is always accurate
|
||||
custom_attributes[CAPTAIN_DOCUMENTS_USAGE] = captain_documents.count
|
||||
save
|
||||
end
|
||||
|
||||
def subscribed_features
|
||||
plan_features = InstallationConfig.find_by(name: 'CHATWOOT_CLOUD_PLAN_FEATURES')&.value
|
||||
return [] if plan_features.blank?
|
||||
|
||||
plan_features[plan_name]
|
||||
end
|
||||
|
||||
def captain_monthly_limit
|
||||
default_limits = default_captain_limits
|
||||
|
||||
{
|
||||
documents: self[:limits][CAPTAIN_DOCUMENTS] || default_limits['documents'],
|
||||
responses: self[:limits][CAPTAIN_RESPONSES] || default_limits['responses']
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_captain_limits(type)
|
||||
total_count = captain_monthly_limit[type.to_s].to_i
|
||||
|
||||
consumed = if type == :documents
|
||||
custom_attributes[CAPTAIN_DOCUMENTS_USAGE].to_i || 0
|
||||
else
|
||||
custom_attributes[CAPTAIN_RESPONSES_USAGE].to_i || 0
|
||||
end
|
||||
|
||||
consumed = 0 if consumed.negative?
|
||||
|
||||
{
|
||||
total_count: total_count,
|
||||
current_available: (total_count - consumed).clamp(0, total_count),
|
||||
consumed: consumed
|
||||
}
|
||||
end
|
||||
|
||||
def default_captain_limits
|
||||
max_limits = { documents: ChatwootApp.max_limit, responses: ChatwootApp.max_limit }.with_indifferent_access
|
||||
zero_limits = { documents: 0, responses: 0 }.with_indifferent_access
|
||||
plan_quota = InstallationConfig.find_by(name: 'CAPTAIN_CLOUD_PLAN_LIMITS')&.value
|
||||
|
||||
# If there are no limits configured, we allow max usage
|
||||
return max_limits if plan_quota.blank?
|
||||
|
||||
# if there is plan_quota configred, but plan_name is not present, we return zero limits
|
||||
return zero_limits if plan_name.blank?
|
||||
|
||||
begin
|
||||
# Now we parse the plan_quota and return the limits for the plan name
|
||||
# but if there's no plan_name present in the plan_quota, we return zero limits
|
||||
plan_quota = JSON.parse(plan_quota) if plan_quota.present?
|
||||
plan_quota[plan_name.downcase] || zero_limits
|
||||
rescue StandardError
|
||||
# if there's any error in parsing the plan_quota, we return max limits
|
||||
# this is to ensure that we don't block the user from using the product
|
||||
max_limits
|
||||
end
|
||||
end
|
||||
|
||||
def plan_name
|
||||
custom_attributes['plan_name']
|
||||
end
|
||||
|
||||
def agent_limits
|
||||
subscribed_quantity = custom_attributes['subscribed_quantity']
|
||||
subscribed_quantity || get_limits(:agents)
|
||||
end
|
||||
|
||||
def get_limits(limit_name)
|
||||
config_name = "ACCOUNT_#{limit_name.to_s.upcase}_LIMIT"
|
||||
return self[:limits][limit_name.to_s] if self[:limits][limit_name.to_s].present?
|
||||
|
||||
return GlobalConfig.get(config_name)[config_name] if GlobalConfig.get(config_name)[config_name].present?
|
||||
|
||||
ChatwootApp.max_limit
|
||||
end
|
||||
|
||||
def validate_limit_keys
|
||||
errors.add(:limits, ': Invalid data') unless self[:limits].is_a? Hash
|
||||
self[:limits] = {} if self[:limits].blank?
|
||||
|
||||
limit_schema = {
|
||||
'type' => 'object',
|
||||
'properties' => {
|
||||
'inboxes' => { 'type': 'number' },
|
||||
'agents' => { 'type': 'number' },
|
||||
'captain_responses' => { 'type': 'number' },
|
||||
'captain_documents' => { 'type': 'number' }
|
||||
},
|
||||
'required' => [],
|
||||
'additionalProperties' => false
|
||||
}
|
||||
|
||||
errors.add(:limits, ': Invalid data') unless JSONSchemer.schema(limit_schema).valid?(self[:limits])
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user