Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
thalia
concrexit
Commits
bdf47e1b
Verified
Commit
bdf47e1b
authored
Jan 20, 2019
by
Sébastiaan Versteeg
Browse files
Start work on Conscribo member sync
parent
81642569
Changes
5
Hide whitespace changes
Inline
Side-by-side
website/members/management/commands/conscribosync.py
0 → 100644
View file @
bdf47e1b
import
logging
from
django.conf
import
settings
from
django.core.management.base
import
BaseCommand
from
django.template.defaultfilters
import
date
from
requests
import
HTTPError
from
members.models
import
Member
from
utils.conscribo.api
import
ConscriboApi
,
ResultException
from
utils.conscribo.objects
import
Command
as
ApiCommand
logger
=
logging
.
getLogger
(
__name__
)
class
Command
(
BaseCommand
):
def
add_arguments
(
self
,
parser
):
parser
.
add_argument
(
'--dry-run'
,
action
=
'store_true'
,
dest
=
'dry-run'
,
default
=
False
,
help
=
'Dry run instead of syncing for real'
,
)
def
handle
(
self
,
*
args
,
**
options
):
api
=
ConscriboApi
(
settings
.
CONSCRIBO_ACCOUNT
,
settings
.
CONSCRIBO_USER
,
settings
.
CONSCRIBO_PASSWORD
)
try
:
relations_response
=
api
.
single_request
(
'listRelations'
,
entityType
=
'lid'
,
requestedFields
=
{
'fieldName'
:
[
'website_id'
,
'code'
]
},
)
relations_response
.
raise_for_status
()
relations_response
=
relations_response
.
data
current_relations
=
{}
if
len
(
relations_response
.
get
(
'relations'
))
>
0
:
current_relations
=
{
int
(
r
.
get
(
'website_id'
)):
r
.
get
(
'code'
,
None
)
for
r
in
relations_response
.
get
(
'relations'
).
values
()
}
replace_commands
=
[]
for
member
in
Member
.
current_members
.
all
():
code
=
current_relations
.
pop
(
member
.
pk
,
None
)
profile
=
member
.
profile
fields
=
{
'website_id'
:
member
.
pk
,
'voornaam'
:
member
.
first_name
,
'naam'
:
member
.
last_name
,
'einddatum_lidmaatschap'
:
date
(
member
.
current_membership
.
until
,
'Y-m-d'
),
'e_mailadres'
:
member
.
email
,
'straatnaam'
:
profile
.
address_street
,
'postcode'
:
profile
.
address_postal_code
,
'plaats'
:
profile
.
address_city
,
'land'
:
'Nederland'
,
'bankrekeningnummer'
:
{
'name'
:
''
,
'bic'
:
''
,
'iban'
:
profile
.
bank_account
,
},
}
replace_commands
.
append
(
ApiCommand
(
command
=
'ReplaceRelation'
,
entityType
=
'lid'
,
fields
=
fields
,
code
=
code
,
))
delete_commands
=
[]
for
website_id
,
code
in
current_relations
.
items
():
delete_commands
.
append
(
ApiCommand
(
command
=
'DeleteRelation'
,
entityType
=
'lid'
,
code
=
code
,
website_id
=
website_id
# not used by server
))
delete_responses
=
api
.
multi_request
(
delete_commands
)
for
response
in
delete_responses
:
if
not
response
.
success
:
logger
.
debug
(
response
.
notifications
)
website_id
=
delete_commands
[
response
.
request_sequence
].
data
.
get
(
'website_id'
)
code
=
delete_commands
[
response
.
request_sequence
].
data
.
get
(
'code'
)
member
=
Member
.
objects
.
get
(
pk
=
website_id
)
fields
=
{
'website_id'
:
member
.
pk
,
'voornaam'
:
member
.
first_name
,
'naam'
:
member
.
last_name
,
'einddatum_lidmaatschap'
:
date
(
member
.
latest_membership
.
until
,
'Y-m-d'
),
'e_mailadres'
:
''
,
'straatnaam'
:
''
,
'postcode'
:
''
,
'plaats'
:
''
,
'land'
:
''
,
'bankrekeningnummer'
:
{
'name'
:
''
,
'bic'
:
''
,
'iban'
:
''
,
},
}
replace_commands
.
append
(
ApiCommand
(
command
=
'ReplaceRelation'
,
entityType
=
'lid'
,
fields
=
fields
,
code
=
code
,
))
replace_responses
=
api
.
multi_request
(
replace_commands
)
for
response
in
replace_responses
:
if
not
response
.
success
:
logger
.
debug
(
response
.
notifications
)
except
HTTPError
as
e
:
logger
.
error
(
'HTTP error syncing relations to Conscribo'
,
e
)
except
ResultException
as
e
:
logger
.
error
(
'Server error syncing relations to Conscribo'
,
e
)
website/thaliawebsite/settings/settings.py
View file @
bdf47e1b
...
...
@@ -283,6 +283,11 @@ MAILINGLIST_API_SECRET = ''
# Members Sentry API key
MEMBERS_SENTRY_API_SECRET
=
''
# Conscribo settings
CONSCRIBO_ACCOUNT
=
''
CONSCRIBO_USER
=
''
CONSCRIBO_PASSWORD
=
''
# Activemembers NextCloud API key
ACTIVEMEMBERS_NEXTCLOUD_API_SECRET
=
''
...
...
website/utils/conscribo/__init__.py
0 → 100644
View file @
bdf47e1b
website/utils/conscribo/api.py
0 → 100644
View file @
bdf47e1b
import
requests
from
utils.conscribo.objects
import
*
class
ConscriboApi
:
def
__init__
(
self
,
account
,
username
,
password
):
self
.
_session
=
requests
.
session
()
self
.
_endpoint
=
(
f
'https://secure.conscribo.nl'
f
'/
{
account
}
/request.json'
)
self
.
_headers
=
{
"X-Conscribo-API-Version"
:
"0.20161212"
}
self
.
authenticate
(
username
,
password
)
def
single_request
(
self
,
command
,
**
params
):
response
=
self
.
_session
.
post
(
self
.
_endpoint
,
Request
.
single
(
command
,
**
params
).
json
(),
headers
=
self
.
_headers
)
response
.
raise_for_status
()
result
=
Result
.
single
(
response
.
json
())
return
result
def
multi_request
(
self
,
commands
):
if
len
(
commands
)
==
1
:
return
[
self
.
single_request
(
commands
[
0
])]
response
=
self
.
_session
.
post
(
self
.
_endpoint
,
Request
.
multi
(
commands
).
json
(),
headers
=
self
.
_headers
)
response
.
raise_for_status
()
return
Result
.
multi
(
response
.
json
())
def
authenticate
(
self
,
username
,
password
):
result
=
self
.
single_request
(
command
=
'authenticateWithUserAndPass'
,
userName
=
username
,
passPhrase
=
password
)
self
.
_headers
.
update
({
"X-Conscribo-SessionId"
:
result
.
data
.
get
(
'sessionId'
,
None
)
})
website/utils/conscribo/objects.py
0 → 100644
View file @
bdf47e1b
import
json
class
_JsonSerializable
(
object
):
@
property
def
data
(
self
)
->
object
:
return
'not implemented'
def
json
(
self
)
->
str
:
return
json
.
dumps
(
self
.
data
)
def
__str__
(
self
)
->
str
:
return
self
.
json
()
class
Command
(
_JsonSerializable
):
def
__init__
(
self
,
command
,
**
params
)
->
None
:
self
.
_command
=
command
self
.
_params
=
params
@
property
def
data
(
self
)
->
dict
:
return
{
'command'
:
self
.
_command
,
**
self
.
_params
,
}
class
Request
(
_JsonSerializable
):
def
__init__
(
self
,
commands
)
->
None
:
self
.
_commands
=
commands
@
property
def
data
(
self
)
->
dict
:
if
len
(
self
.
_commands
)
==
1
:
return
{
'request'
:
self
.
_commands
[
0
].
data
}
return
{
'requests'
:
{
'request'
:
[{
**
v
.
data
,
'requestSequence'
:
str
(
k
)}
for
k
,
v
in
enumerate
(
self
.
_commands
)]
}
}
@
staticmethod
def
single
(
command
,
**
params
)
->
_JsonSerializable
:
if
isinstance
(
command
,
Command
):
return
Request
([
command
])
return
Request
([
Command
(
command
,
**
params
)])
@
staticmethod
def
multi
(
commands
)
->
_JsonSerializable
:
return
Request
(
commands
)
class
ResultException
(
Exception
):
def
__init__
(
self
,
notifications
):
msg
=
"Error occurred on server:
\n
"
+
"
\n
"
.
join
(
notifications
)
super
(
ResultException
,
self
).
__init__
(
msg
)
class
Result
(
object
):
def
__init__
(
self
,
data
)
->
None
:
self
.
_data
=
data
self
.
_success
=
self
.
_data
.
pop
(
'success'
,
False
)
self
.
_request_sequence
=
self
.
_data
.
pop
(
'requestSequence'
,
0
)
self
.
_notifications
=
self
.
_data
.
pop
(
'notifications'
,
{
'notification'
:
[]
}).
get
(
'notification'
)
@
staticmethod
def
single
(
data
):
return
Result
(
data
.
get
(
'result'
,
{}))
@
staticmethod
def
multi
(
data
):
return
[
Result
(
result
)
for
result
in
data
.
get
(
'results'
,
{
'result'
:
[]}).
get
(
'result'
,
None
)]
@
property
def
success
(
self
):
return
self
.
_success
@
property
def
notifications
(
self
):
return
self
.
_notifications
@
property
def
request_sequence
(
self
):
return
self
.
_request_sequence
@
property
def
data
(
self
):
return
self
.
_data
def
raise_for_status
(
self
):
if
not
self
.
success
:
raise
ResultException
(
self
.
notifications
)
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