Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
65 changes: 65 additions & 0 deletions lms/djangoapps/appsembler_api/apidocs.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,71 @@ Cache-Control: no-cache
}
```

### Update user account

This endpoint allows to update a user account. Receives a lookup parameter and N optional parameters which are all the attributes that needs to be updated.
The endpoint can update email, all available profile fields and also has support for [registration extension form fields](https://github.com/open-craft/custom-form-app).

* URL: `/appsembler_api/v0/accounts/update_user
* Method: `POST`
* Data Params
* Required:
* `user_lookup` # can be username or email
* Optional:
* `email` # user's email
* `name` # user full name
* `country` # country iso code, ex: `ES`, `UY`, `US`
* `gender` # user gender, accepted values `m`, `f` or `o`
* `level_of_education` # user education, accepted values `p`, `m`, `b`, `a`, `hs`, `jhs`, `el`, `none` or `other`,
* `year_of_birth` # four digit year as string
* `city` # text
* `mailing_address` # long text
* `language` # language iso code, ex 'ES', 'EN'
* `goals` # long text
* `bio` # text

You also can send extended profile form fiels, but that depends on every installation, you'll need to find the [registration extension form app fork](https://github.com/open-craft/custom-form-app) that is installed on the instance, and check the field names, and accepted values.

* Success Response
* Code: 200
* Content: Success message and list of updated fields and values
```
{
"success": "The following fields has been updated: name=Doe, John, country=ES"
}
```
* Error Responses:
* Code: 404 NOT FOUND
* Reason: User not exists

* Error Responses:
* Code: 400 NOT FOUND
* Reason: No user lookup parameter sent

* Example call:
```
POST /appsembler_api/v0/accounts/update_user
Host: example.com
Content-Type: application/json
Authorization: Bearer cbf6a5de322cf6a4323c957a882xy1s321c954b86
Cache-Control: no-cache
{
"user_lookup": "staff@example.com",
"emai": "new_staff@example.com",
"name": "Staff New Name",
"country": "US",
"gender": "f",
"level_of_education": "m",
"year_of_birth": "2000",
"city": "Montevideo",
"mailing_address": "A streen and a number 2345 FL, USA",
"language": "es",
"goals": "To be famous",
"bio": "I'm not famous yet"
"district": "101815" # a custom form field
}
```

### Check Existing Username

This endpoint is a tool to check if an user exists given the username.
Expand Down
1 change: 1 addition & 0 deletions lms/djangoapps/appsembler_api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
url(r'^accounts/user_without_password', views.CreateUserAccountWithoutPasswordView.as_view(), name="create_user_account_without_password_api"),
url(r'^accounts/create', views.CreateUserAccountView.as_view(), name="create_user_account_api"),
url(r'^accounts/connect', views.UserAccountConnect.as_view(), name="user_account_connect_api"),
url(r'^accounts/update_user', views.UpdateUserAccount.as_view(), name="user_account_update_user"),
url(r'^accounts/get-user/(?P<username>[\w.+-]+)', views.GetUserAccountView.as_view(), name="get_user_account_api"),

# bulk enrollment API
Expand Down
106 changes: 104 additions & 2 deletions lms/djangoapps/appsembler_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.http import Http404
from django.db.models import Q
from django.core.validators import validate_email

from rest_framework.views import APIView
Expand All @@ -26,9 +27,10 @@
IsStaffOrOwner, ApiKeyHeaderPermissionIsAuthenticated
)

from student.forms import get_registration_extension_form
from student.views import create_account_with_params
from student.models import CourseEnrollment, EnrollmentClosedError, \
CourseFullError, AlreadyEnrolledError
CourseFullError, AlreadyEnrolledError, UserProfile

from course_modes.models import CourseMode
from courseware.courses import get_course_by_id
Expand Down Expand Up @@ -241,6 +243,107 @@ def post(self, request):
return response


class UpdateUserAccount(APIView):
""" HTTP endpoint for updating and user account """

authentication_classes = OAuth2AuthenticationAllowInactiveUser,
permission_classes = IsStaffOrOwner,

def post(self, request):
"""
This endpoint allows to change user attributes including email, profile
attributes and extended profile fields. Receives one mandatory param
user_lookup that can be an email or username to lookup the user to
update and the rest of parameters are option. Any attribute to update
must be sent in key:val JSON format.

URL: /appsembler_api/v0/accounts/update_user
Arguments:
request (HttpRequest)
JSON (application/json)
{
"user_lookup": email or username to lookup the user to update,
# mandatory ex: "staff4@example.com" or "staff4"

"email": "staff@example.com",
"bio": "this is my bio",
"country": "BR"
}
Returns:
HttpResponse: 200 on success, {"success ": "list of updated params"}
HttpResponse: 404 if the doesn't exists
HttpResponse: 400 Incorrect parameters, basically if username or
email parameter is not sent
"""
data = request.data

if data['user_lookup'].strip() == "":
errors = {"lookup_error": "No user lookup has been provided"}
return Response(errors, status=400)

user = User.objects.filter(
Q(username=data['user_lookup']) | Q(email=data['user_lookup'])
)

if user:
user = user[0]
else:
errors = {
"user_not_found": "The user for the Given username or email doesn't exists"
}
return Response(errors, status=404)

updated_fields = {}

# update email
if 'email' in data and data['email'] != user.email:
user_exists = check_account_exists(email=data['email'])
if user_exists:
errors = {"integrity_error": "the user email you're trying to set already belongs to another user"}
return Response(errors, status=400)

user.email = data['email']
user.save()
updated_fields.update({'email': data['email']})

# update profile fields
profile_fields = [
"name", "level_of_education", "gender", "mailing_address", "city",
"country", "goals", "bio", "year_of_birth", "language"
]

profile_fields_to_update = {}
for field in profile_fields:
if field in data:
profile_fields_to_update[field] = data[field]

if len(profile_fields_to_update):
UserProfile.objects.filter(user=user).update(**profile_fields_to_update)
updated_fields.update(profile_fields_to_update)

# If there is an exension form fields installed update them too
custom_profile_fields_to_update = {}
custom_form = get_registration_extension_form()

if custom_form is not None:
for custom_field in custom_form.fields:
if custom_field in data:
custom_profile_fields_to_update[custom_field] = data[custom_field]
updated_fields.update(custom_profile_fields_to_update)

if len(custom_profile_fields_to_update):
custom_form.Meta.model.objects.filter(user=user).update(
**custom_profile_fields_to_update)

return Response(
{"success": "The following fields has been updated: {}".format(
', '.join(
'{}={}'.format(f, v) for f, v in updated_fields.items())
)
},
status=200)


class GetUserAccountView(APIView):
authentication_classes = OAuth2AuthenticationAllowInactiveUser,
permission_classes = IsStaffOrOwner,
Expand All @@ -260,7 +363,6 @@ def get(self, request, username):
"""
try:
account_settings = User.objects.select_related('profile').get(username=username)
print account_settings
except User.DoesNotExist:
return Response(
status=status.HTTP_404_NOT_FOUND
Expand Down