Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Birin Sanchez
Keel - LDH Middleware
Commits
d7310ed9
Commit
d7310ed9
authored
May 15, 2019
by
Noe Nieto
💬
Browse files
Merge branch 'master' of source.puri.sm:liberty/ldh_middleware
parents
e3e2f58b
4dec867e
Changes
7
Hide whitespace changes
Inline
Side-by-side
limitmonitor/common.py
0 → 100644
View file @
d7310ed9
import
logging
import
datetime
from
django.conf
import
settings
from
django.utils
import
timezone
from
purist.models
import
get_woo_connection
from
purist.limitmonitor
import
ParserContainer
from
limitmonitor.models
import
ExternalCredit
,
ExternalBundle
from
limitmonitor.tunnel
import
TunnelManager
logger
=
logging
.
getLogger
(
__name__
)
def
get_username_from_woo_customer_id
(
customer_id
,
woo
=
None
):
if
woo
is
None
:
woo
=
get_woo_connection
()
try
:
query
=
"customers/"
+
str
(
customer_id
)
result
=
woo
.
get
(
query
).
json
()
return
result
[
"username"
]
except
Exception
:
logger
.
exception
(
"Could not retrieve username for customer_id "
+
str
(
customer_id
))
return
"invalid"
def
parse_subscription
(
json_entry
):
subscription_id
=
str
(
json_entry
[
"id"
])
# validation
if
len
(
json_entry
[
"line_items"
])
!=
1
:
raise
Exception
(
"Too many line items in subscription %s"
%
(
id
,
))
line_item
=
json_entry
[
"line_items"
][
0
]
quantity
=
line_item
[
"quantity"
]
if
quantity
!=
1
:
raise
Exception
(
"Bad quantity %s in subscription %s"
%
(
quantity
,
id
,
))
# calculate next renewal date
next_renewal_naive
=
datetime
.
datetime
.
strptime
(
json_entry
[
"next_payment_date"
],
"%Y-%m-%dT%H:%M:%S"
)
next_renewal
=
timezone
.
make_aware
(
next_renewal_naive
)
# get account name
username
=
get_username_from_woo_customer_id
(
json_entry
[
"customer_id"
])
# bundle_key value is different depending on the subscription
# having variations or not
if
line_item
.
get
(
'variation_id'
)
!=
0
:
bundle_key
=
line_item
.
get
(
'variation_id'
)
else
:
bundle_key
=
line_item
.
get
(
'product_id'
)
# create result
result
=
{
"parser"
:
ParserContainer
.
WOO_SUBSCRIPTION_V1
,
"external_key"
:
subscription_id
,
"label"
:
json_entry
[
"number"
],
"bundle_key"
:
bundle_key
,
"bundle_label"
:
str
(
line_item
[
"name"
]),
"quantity"
:
1
,
"account"
:
username
,
"next_renewal"
:
next_renewal
,
"status"
:
json_entry
[
"status"
]
}
return
result
def
get_user_subscriptions
(
user
):
user_wc_id
=
user
.
get_woocommerce_id
()
if
user_wc_id
is
None
:
# The user does not have WC account
return
None
woo
=
get_woo_connection
()
subscriptions
=
woo
.
get
(
'subscriptions?customer={}'
.
format
(
user_wc_id
)).
json
()
if
len
(
subscriptions
)
>=
1
:
return
subscriptions
else
:
return
None
def
subscription_was_processed
(
parsed_sub
,
overwrite
=
False
):
"""Returns an ExternalCredit from the DB if the subscription was
already processed. If the subscription was not already processed
it returns a new ExternalCredit created from parsed_sub data with
is_converted=False.
If overwrite is set to True the existing ExternalCredit is
overwritten with new values from parsed_sub.
"""
try
:
ext_cred
=
ExternalCredit
.
objects
.
get
(
external_key
=
parsed_sub
[
'external_key'
])
if
overwrite
:
ext_cred
.
parser
=
parsed_sub
[
"parser"
]
ext_cred
.
external_key
=
parsed_sub
[
"external_key"
]
ext_cred
.
label
=
parsed_sub
[
"label"
]
ext_cred
.
bundle_key
=
parsed_sub
[
"bundle_key"
]
ext_cred
.
bundle_label
=
parsed_sub
[
"bundle_label"
]
ext_cred
.
quantity
=
parsed_sub
[
"quantity"
]
ext_cred
.
account_name
=
parsed_sub
[
"account"
]
ext_cred
.
additional_data
=
"None"
ext_cred
.
is_converted
=
False
except
ExternalCredit
.
DoesNotExist
:
ext_cred
=
ExternalCredit
(
parser
=
parsed_sub
[
"parser"
],
external_key
=
parsed_sub
[
"external_key"
],
label
=
parsed_sub
[
"label"
],
bundle_key
=
parsed_sub
[
"bundle_key"
],
bundle_label
=
parsed_sub
[
"bundle_label"
],
quantity
=
parsed_sub
[
"quantity"
],
account_name
=
parsed_sub
[
"account"
],
additional_data
=
"None"
,
is_converted
=
False
,
)
return
ext_cred
def
get_services_from_bundle
(
bundle_key
):
ext_buns
=
ExternalBundle
.
objects
.
filter
(
external_key
=
bundle_key
)
result
=
[]
for
ext_bun
in
ext_buns
:
result
.
append
(
ext_bun
.
service
)
return
result
def
forced_update
(
user
):
subscriptions
=
get_user_subscriptions
(
user
)
if
subscriptions
is
None
:
logger
.
info
(
'User {} has no subscriptions.'
.
format
(
user
.
username
))
return
for
sub
in
subscriptions
:
parsed_sub
=
parse_subscription
(
sub
)
if
parsed_sub
[
'bundle_key'
]
not
in
settings
.
WOOSUB1_PRODUCT_LIST
:
logger
.
info
(
'Subscription {} does not belong '
'to Librem One'
.
format
(
parsed_sub
[
'bundle_key'
]))
continue
# Skip this subscription as is not a product we care of
ext_cred
=
subscription_was_processed
(
parsed_sub
,
overwrite
=
True
)
error
=
'Subscription successfully enabled through forced_update'
ext_cred
.
updated_date
=
timezone
.
now
()
bndl_srvs
=
set
(
get_services_from_bundle
(
parsed_sub
[
'bundle_key'
]))
cur_srvs
=
set
(
user
.
get_enabled_limits
())
if
parsed_sub
[
'status'
]
==
'active'
:
srv_to_enable
=
bndl_srvs
-
cur_srvs
srv_to_disable
=
cur_srvs
-
bndl_srvs
srv_to_reenable
=
bndl_srvs
&
cur_srvs
is_pending
=
False
is_converted
=
True
try
:
# Disable services
for
srvn
in
srv_to_disable
:
serv
=
user
.
limit_set
.
get
(
service
=
srvn
)
serv
.
disable
()
serv
.
save
()
# Enable services
for
srvn
in
srv_to_enable
|
srv_to_reenable
:
serv
=
user
.
limit_set
.
get
(
service
=
srvn
)
serv
.
enable
(
parsed_sub
[
'next_renewal'
])
serv
.
save
()
except
TunnelManager
.
TerminateAccountError
as
e1
:
error
=
'{}: {}'
.
format
(
ext_cred
.
external_key
,
repr
(
e1
))
is_pending
=
True
is_converted
=
False
except
Exception
as
e2
:
is_pending
=
True
is_converted
=
False
error
=
'{}: {}'
.
format
(
ext_cred
.
external_key
,
repr
(
e2
))
finally
:
if
hasattr
(
user
,
'chosenreward'
):
user
.
chosenreward
.
is_pending
=
is_pending
user
.
chosenreward
.
save
()
ext_cred
.
error_message
=
error
ext_cred
.
is_converted
=
is_converted
ext_cred
.
save
()
# TODO: process other subscription statuses
else
:
logger
.
info
(
'Subscription {} for user {} status is: {}'
.
format
(
parsed_sub
[
'label'
],
user
.
username
,
parsed_sub
[
'status'
]))
limitmonitor/management/commands/forced_update.py
0 → 100644
View file @
d7310ed9
from
django.core.management.base
import
BaseCommand
from
django.core.validators
import
EmailValidator
,
ValidationError
from
django.conf
import
settings
from
limitmonitor.common
import
forced_update
from
purist.models
import
User
class
Command
(
BaseCommand
):
help
=
'Update user enabled services according to WooCommerce
\
subscription.'
def
add_arguments
(
self
,
parser
):
parser
.
add_argument
(
'email'
,
type
=
str
,
help
=
'This is the email of the user that will get
\
services updated according to subscription.'
)
def
handle
(
self
,
*
args
,
**
options
):
ev
=
EmailValidator
()
email
=
options
[
'email'
]
try
:
ev
(
email
)
except
ValidationError
as
e
:
self
.
stdout
.
write
(
repr
(
e
))
return
(
username
,
domain
)
=
email
.
split
(
'@'
)
if
domain
!=
settings
.
SITE_DOMAIN
:
msg
=
'{} does not belong to {} domain'
self
.
stdout
.
write
(
msg
.
format
(
email
,
settings
.
SITE_DOMAIN
))
return
try
:
user
=
User
.
objects
.
get
(
username
=
username
)
except
User
.
DoesNotExist
:
msg
=
'User {} does not exist.'
.
format
(
email
)
self
.
stdout
.
write
(
msg
)
return
forced_update
(
user
)
msg
=
'Services update forced on user {}.'
.
format
(
email
)
self
.
stdout
.
write
(
msg
)
limitmonitor/models.py
View file @
d7310ed9
...
...
@@ -40,7 +40,7 @@ class Limit(models.Model):
def
active_label
(
self
):
if
self
.
is_
active
:
if
self
.
is_
enabled
()
:
return
"Yes"
else
:
return
"No"
...
...
@@ -156,9 +156,42 @@ class Limit(models.Model):
self
.
is_active
=
True
else
:
raise
Exception
(
"Invalid a
ctivation attempt
. Service not recognised."
)
"Invalid a
ttempt to enable
. Service not recognised."
)
self
.
renewal_date
=
ren_date
def
disable
(
self
):
if
self
.
service
==
settings
.
LM_SERVICES
.
TUNNEL
:
self
.
user
.
terminate_tunnel_account
()
self
.
is_active
=
False
elif
self
.
service
==
settings
.
LM_SERVICES
.
CHAT
:
self
.
user
.
remove_ldap_group
(
"chat"
)
self
.
is_active
=
False
elif
self
.
service
==
settings
.
LM_SERVICES
.
MAIL
:
self
.
user
.
remove_ldap_group
(
"mail"
)
self
.
is_active
=
False
elif
self
.
service
==
settings
.
LM_SERVICES
.
SOCIAL
:
self
.
user
.
remove_ldap_group
(
"social"
)
self
.
is_active
=
False
elif
self
.
service
==
settings
.
LM_SERVICES
.
XMPP
:
self
.
user
.
remove_ldap_group
(
"xmpp"
)
self
.
is_active
=
False
elif
self
.
service
==
settings
.
LM_SERVICES
.
GROUP
:
self
.
is_active
=
False
else
:
raise
Exception
(
"Invalid attempt to disable. Service not recognised."
)
self
.
renewal_date
=
None
def
is_enabled
(
self
):
"""If the limit is not TUNNEL returns the value of is_acitve. For
TUNNEL limit returns True if there is time remaining to use
the service.
"""
if
self
.
service
==
settings
.
LM_SERVICES
.
TUNNEL
:
return
self
.
remaining_use_time
().
total_seconds
()
>
0
return
self
.
is_active
class
ExternalBundle
(
models
.
Model
):
"""Class used to represent external bundles that exist in external
entities like WooCommerce
...
...
limitmonitor/task_resources/subscription.py
View file @
d7310ed9
import
datetime
from
django.utils
import
timezone
from
django.conf
import
settings
from
purist.models
import
get_woo_connection
from
celery.utils.log
import
get_task_logger
from
limitmonitor.models
import
ExternalCredit
,
ExternalBundle
from
cart.models
import
ChosenReward
from
limitmonitor.common
import
parse_subscription
,
get_user_subscriptions
,
\
subscription_was_processed
,
get_services_from_bundle
logger
=
get_task_logger
(
__name__
)
def
get_username_from_woo_customer_id
(
customer_id
,
woo
=
None
):
if
woo
is
None
:
woo
=
get_woo_connection
()
try
:
query
=
"customers/"
+
str
(
customer_id
)
result
=
woo
.
get
(
query
).
json
()
return
result
[
"username"
]
except
Exception
:
logger
.
exception
(
"Could not retrieve username for customer_id "
+
str
(
customer_id
))
return
"invalid"
def
parse_subscription
(
json_entry
):
subscription_id
=
str
(
json_entry
[
"id"
])
# validation
if
len
(
json_entry
[
"line_items"
])
!=
1
:
raise
Exception
(
"Too many line items in subscription %s"
%
(
id
,
))
line_item
=
json_entry
[
"line_items"
][
0
]
quantity
=
line_item
[
"quantity"
]
if
quantity
!=
1
:
raise
Exception
(
"Bad quantity %s in subscription %s"
%
(
quantity
,
id
,
))
# calculate next renewal date
next_renewal_naive
=
datetime
.
datetime
.
strptime
(
json_entry
[
"next_payment_date"
],
"%Y-%m-%dT%H:%M:%S"
)
next_renewal
=
timezone
.
make_aware
(
next_renewal_naive
)
# get account name
username
=
get_username_from_woo_customer_id
(
json_entry
[
"customer_id"
])
# bundle_key value is different depending on the subscription
# having variations or not
if
line_item
.
get
(
'variation_id'
)
!=
0
:
bundle_key
=
line_item
.
get
(
'variation_id'
)
else
:
bundle_key
=
line_item
.
get
(
'product_id'
)
# create result
result
=
{
# FIXME: this is WOO_SUBSCRIPTION_V1 from purist.limitmonitor
"parser"
:
2
,
"external_key"
:
subscription_id
,
"label"
:
json_entry
[
"number"
],
"bundle_key"
:
bundle_key
,
"bundle_label"
:
str
(
line_item
[
"name"
]),
"quantity"
:
1
,
"account"
:
username
,
"next_renewal"
:
next_renewal
,
"status"
:
json_entry
[
"status"
]
}
return
result
def
get_user_subscriptions
(
user
):
user_wc_id
=
user
.
get_woocommerce_id
()
if
user_wc_id
is
None
:
# The user does not have WC account
return
None
woo
=
get_woo_connection
()
subscriptions
=
woo
.
get
(
'subscriptions?customer={}'
.
format
(
user_wc_id
)).
json
()
if
len
(
subscriptions
)
>=
1
:
return
subscriptions
else
:
return
None
def
subscription_was_processed
(
parsed_sub
):
"""Returns an ExternalCredit fron the DB if the subscription was
already processed. If the subscription was not already
processed it returns a new ExternalCredit created from parsed_sub
data with is_converted=False
"""
try
:
ext_cred
=
ExternalCredit
.
objects
.
get
(
external_key
=
parsed_sub
[
'external_key'
])
except
ExternalCredit
.
DoesNotExist
:
ext_cred
=
ExternalCredit
(
parser
=
parsed_sub
[
"parser"
],
external_key
=
parsed_sub
[
"external_key"
],
label
=
parsed_sub
[
"label"
],
bundle_key
=
parsed_sub
[
"bundle_key"
],
bundle_label
=
parsed_sub
[
"bundle_label"
],
quantity
=
parsed_sub
[
"quantity"
],
account_name
=
parsed_sub
[
"account"
],
additional_data
=
"None"
,
is_converted
=
False
,
)
return
ext_cred
def
get_services_from_bundle
(
bundle_key
):
ext_buns
=
ExternalBundle
.
objects
.
filter
(
external_key
=
bundle_key
)
result
=
[]
for
ext_bun
in
ext_buns
:
result
.
append
(
ext_bun
.
service
)
return
result
def
process_pending_registrations_user
(
user
):
subscriptions
=
get_user_subscriptions
(
user
)
...
...
@@ -153,10 +39,7 @@ def process_pending_registrations_user(user):
ext_cred
.
is_converted
=
True
is_pending
=
False
except
Exception
as
e
:
error
=
repr
(
e
)
ext_cred
.
error_message
=
'{}: {}'
.
format
(
ext_cred
.
external_key
,
error
)
error
=
'{}: {}'
.
format
(
ext_cred
.
external_key
,
repr
(
e
))
ext_cred
.
is_converted
=
False
is_pending
=
True
finally
:
...
...
limitmonitor/tunnel.py
View file @
d7310ed9
...
...
@@ -6,6 +6,14 @@ BASE_URL = '{host}/resellers/api/v1/{operation}'
class
TunnelManager
(
object
):
class
TerminateAccountError
(
Exception
):
"""Raised when we cannot terminate an account. This need to be
propagated through the stack so the program using
terminate_account() can decide what to do.
"""
pass
def
__init__
(
self
,
partner_id
,
secret
,
host
):
self
.
partner_id
=
partner_id
...
...
@@ -50,7 +58,8 @@ class TunnelManager(object):
r
=
requests
.
post
(
url
,
data
=
payload
)
if
r
.
status_code
==
200
:
return
r
.
json
()
return
None
raise
self
.
TerminateAccountError
(
"Account {} couldn't be terminated."
.
format
(
username
))
def
find_account
(
self
):
pass
...
...
limitmonitor/views.py
View file @
d7310ed9
...
...
@@ -21,7 +21,7 @@ def userlimit(request):
none_limit
=
True
for
limit
in
limits
:
label
=
limit
.
service_label
().
upper
()
has_limit
[
label
]
=
limit
.
is_
active
has_limit
[
label
]
=
limit
.
is_
enabled
()
# Default action for services
action_function
[
label
]
=
'.'
if
limit
.
is_active
:
...
...
purist/models.py
View file @
d7310ed9
...
...
@@ -422,6 +422,14 @@ class User(AbstractUser):
return
self
.
username
+
'@'
+
settings
.
EMAIL_DOMAIN
return
self
.
email
def
get_enabled_limits
(
self
):
limits
=
self
.
limit_set
.
all
()
result
=
[]
for
l
in
limits
:
if
l
.
is_enabled
():
result
.
append
(
l
.
service
)
return
result
def
encrypt
(
data
):
# Encrypt data with Fernet
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment