From 805fff07bf329530b55ed1a6548363856ba69fef Mon Sep 17 00:00:00 2001 From: Yash Ladha <201551061@iiitvadodara.ac.in> Date: Sun, 10 Jun 2018 21:47:03 +0530 Subject: [PATCH] Fixes #969 : Added photoURL Change for the user profile (#977) --- .flake8 | 2 +- api/controllers/updateProfile.py | 8 ++--- api/helpers/uploads.py | 2 +- .../{0401105d0287_.py => ba0a1f466b08_.py} | 7 ++-- api/schemas/badges.py | 1 - frontend/app/adapters/profile-image.js | 12 +++++++ .../def-image-component.js | 3 +- .../components/user-component/my-profile.js | 22 +++++++++++++ frontend/app/controllers/my-profile.js | 33 +++++++++++++++++++ frontend/app/models/profile-image.js | 10 ++++++ frontend/app/routes/my-profile.js | 13 ++++++++ frontend/app/styles/partials/all.scss | 1 + frontend/app/styles/partials/profile.scss | 23 +++++++++++++ .../components/user-component/my-profile.hbs | 6 ++-- frontend/app/templates/my-profile.hbs | 2 +- .../tests/unit/adapters/profile-image-test.js | 12 +++++++ .../tests/unit/controllers/my-profile-test.js | 12 +++++++ .../tests/unit/models/profile-image-test.js | 14 ++++++++ 18 files changed, 166 insertions(+), 17 deletions(-) rename api/migrations/versions/{0401105d0287_.py => ba0a1f466b08_.py} (92%) create mode 100644 frontend/app/adapters/profile-image.js create mode 100644 frontend/app/controllers/my-profile.js create mode 100644 frontend/app/models/profile-image.js create mode 100644 frontend/app/styles/partials/profile.scss create mode 100644 frontend/tests/unit/adapters/profile-image-test.js create mode 100644 frontend/tests/unit/controllers/my-profile-test.js create mode 100644 frontend/tests/unit/models/profile-image-test.js diff --git a/.flake8 b/.flake8 index e0b709539..e7885acf9 100644 --- a/.flake8 +++ b/.flake8 @@ -4,5 +4,5 @@ ignore = W191 exclude = .git, __pycache__, - backend/migrations, + api/migrations, site-packages diff --git a/api/controllers/updateProfile.py b/api/controllers/updateProfile.py index 77124f444..57ce6a5f1 100644 --- a/api/controllers/updateProfile.py +++ b/api/controllers/updateProfile.py @@ -9,8 +9,7 @@ PayloadNotFound, ImageNotFound, UserNotFound, - ExtensionNotFound, - PNGNotFound + ExtensionNotFound ) from api.schemas.user import UpdateUserSchema from api.models.user import User @@ -18,7 +17,7 @@ router = Blueprint('updateUserProfile', __name__) -@router.route('/profileImage') +@router.route('/profileImage', methods=['POST']) def update_profile_image(): try: data = request.get_json()['data']['attributes'] @@ -31,9 +30,6 @@ def update_profile_image(): if not data['extension']: return ErrorResponse(ExtensionNotFound().message, 422, {'Content-Type': 'application/json'}).respond() - if data['extension'] != 'png': - return ErrorResponse(PNGNotFound().message, 422, {'Content-Type': 'application/json'}).respond() - image = data['image'] extension = data['extension'] try: diff --git a/api/helpers/uploads.py b/api/helpers/uploads.py index 64fa9ca3f..abcf2f4ea 100644 --- a/api/helpers/uploads.py +++ b/api/helpers/uploads.py @@ -14,7 +14,7 @@ def saveToImage(imageFile=None, extension='.png'): if not os.path.isdir(imageDirectory): os.makedirs(imageDirectory) - imageFile = imageFile.replace('data:image/png;base64,', '') + imageFile = imageFile.replace('data:image/' + extension.split('.')[1] + ';base64,', '') imagePath = os.path.join(imageDirectory, imageName) image = open(imagePath, "wb") image.write(base64.b64decode(imageFile)) diff --git a/api/migrations/versions/0401105d0287_.py b/api/migrations/versions/ba0a1f466b08_.py similarity index 92% rename from api/migrations/versions/0401105d0287_.py rename to api/migrations/versions/ba0a1f466b08_.py index db3e31661..f531a95f2 100644 --- a/api/migrations/versions/0401105d0287_.py +++ b/api/migrations/versions/ba0a1f466b08_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: 0401105d0287 +Revision ID: ba0a1f466b08 Revises: -Create Date: 2018-06-09 18:48:16.814689 +Create Date: 2018-06-10 15:08:00.600923 """ from alembic import op @@ -10,7 +10,7 @@ # revision identifiers, used by Alembic. -revision = '0401105d0287' +revision = 'ba0a1f466b08' down_revision = None branch_labels = None depends_on = None @@ -24,6 +24,7 @@ def upgrade(): sa.Column('password', sa.String(length=100), nullable=True), sa.Column('email', sa.String(length=100), nullable=True), sa.Column('photoURL', sa.String(), nullable=True), + sa.Column('allowed_usage', sa.Integer(), nullable=True), sa.PrimaryKeyConstraint('id') ) op.create_table('Badges', diff --git a/api/schemas/badges.py b/api/schemas/badges.py index 08c9c33f7..057c007c9 100644 --- a/api/schemas/badges.py +++ b/api/schemas/badges.py @@ -90,4 +90,3 @@ class Meta: include_resource_linkage=True, type_='User' ) - diff --git a/frontend/app/adapters/profile-image.js b/frontend/app/adapters/profile-image.js new file mode 100644 index 000000000..dab8d7359 --- /dev/null +++ b/frontend/app/adapters/profile-image.js @@ -0,0 +1,12 @@ +import DS from 'ember-data'; +import ENV from '../config/environment'; + +const { JSONAPIAdapter } = DS; +const { APP } = ENV; + +export default JSONAPIAdapter.extend({ + host : APP.backLink, + pathForType : () => { + return 'update/profileImage'; + } +}); diff --git a/frontend/app/components/background-component/def-image-component.js b/frontend/app/components/background-component/def-image-component.js index 23e624f5d..6c3b02110 100644 --- a/frontend/app/components/background-component/def-image-component.js +++ b/frontend/app/components/background-component/def-image-component.js @@ -2,9 +2,8 @@ import Component from '@ember/component'; export default Component.extend({ init() { - // To be inflated from the backend data this.fingerPrint = window.ASSET_FINGERPRINT_HASH; - return this._super(...arguments); + this._super(...arguments); }, click() { let imageId = this.get('image'); diff --git a/frontend/app/components/user-component/my-profile.js b/frontend/app/components/user-component/my-profile.js index bb93d73f3..63ca707bc 100644 --- a/frontend/app/components/user-component/my-profile.js +++ b/frontend/app/components/user-component/my-profile.js @@ -1,4 +1,26 @@ import Component from '@ember/component'; export default Component.extend({ + init() { + this._super(...arguments); + }, + actions: { + updateProfileImage() { + document.getElementById('profileImageSelector').click(); + }, + + profileImageSelected(event) { + const reader = new FileReader(); + const { target } = event; + const { files } = target; + const [file] = files; + const _this = this; + + reader.onload = () => { + _this.get('sendProfileImage')(reader.result, file.type.split('/')[1]); + }; + + reader.readAsDataURL(file); + } + } }); diff --git a/frontend/app/controllers/my-profile.js b/frontend/app/controllers/my-profile.js new file mode 100644 index 000000000..9fa505bff --- /dev/null +++ b/frontend/app/controllers/my-profile.js @@ -0,0 +1,33 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default Controller.extend({ + routing : service('-routing'), + uid : '', + actions : { + updateProfileImage(profileImageData, extension) { + const _this = this; + const user = this.get('store').peekAll('user'); + user.forEach(user_ => { + _this.set('uid', user_.get('id')); + }); + let profileImage = _this.get('store').createRecord('profile-image', { + image : profileImageData, + uid : _this.uid, + extension : '.' + extension + }); + profileImage.save() + .then(record => { + user.forEach(user_ => { + user_.set('photoURL', record.photoURL); + }); + }) + .catch(err => { + let userErrors = profileImage.get('errors.user'); + if (userErrors !== undefined) { + _this.set('userError', userErrors); + } + }); + } + } +}); diff --git a/frontend/app/models/profile-image.js b/frontend/app/models/profile-image.js new file mode 100644 index 000000000..c9f461616 --- /dev/null +++ b/frontend/app/models/profile-image.js @@ -0,0 +1,10 @@ +import DS from 'ember-data'; + +const { Model, attr } = DS; + +export default Model.extend({ + uid : attr('string'), + image : attr('string'), + extension : attr('string'), + photoURL : attr('string') +}); diff --git a/frontend/app/routes/my-profile.js b/frontend/app/routes/my-profile.js index 6c74252aa..5bf1dafa8 100644 --- a/frontend/app/routes/my-profile.js +++ b/frontend/app/routes/my-profile.js @@ -1,4 +1,17 @@ +import Ember from 'ember'; import Route from '@ember/routing/route'; +const { RSVP, set } = Ember; + export default Route.extend({ + model() { + return RSVP.hash({ + user: this.get('store').peekAll('user').slice(0, 1)[0] + }); + }, + + setupController(controller, model) { + this._super(...arguments); + set(controller, 'user', model.user); + } }); diff --git a/frontend/app/styles/partials/all.scss b/frontend/app/styles/partials/all.scss index ad0d1b710..78b012c24 100644 --- a/frontend/app/styles/partials/all.scss +++ b/frontend/app/styles/partials/all.scss @@ -2,3 +2,4 @@ @import "footer"; @import "overrides"; @import "notifications"; +@import "profile"; diff --git a/frontend/app/styles/partials/profile.scss b/frontend/app/styles/partials/profile.scss new file mode 100644 index 000000000..a272a16ea --- /dev/null +++ b/frontend/app/styles/partials/profile.scss @@ -0,0 +1,23 @@ +.profile-image:hover { + .profile-change { + opacity: 1; + } + + img { + opacity: 0.3; + } +} + + +.profile-change { + bottom: 0; + margin-left: auto; + margin-right: auto; + opacity: 0; + padding-top: 50%; + position: absolute; + text-align: center; + top: 0; + transition: 0.5s ease; + width: 100%; +} diff --git a/frontend/app/templates/components/user-component/my-profile.hbs b/frontend/app/templates/components/user-component/my-profile.hbs index 20bbb07cb..ad41e7274 100644 --- a/frontend/app/templates/components/user-component/my-profile.hbs +++ b/frontend/app/templates/components/user-component/my-profile.hbs @@ -1,8 +1,10 @@
-
- +
+ + +
Change
diff --git a/frontend/app/templates/my-profile.hbs b/frontend/app/templates/my-profile.hbs index 48de9f2f8..75d73c7b9 100644 --- a/frontend/app/templates/my-profile.hbs +++ b/frontend/app/templates/my-profile.hbs @@ -1 +1 @@ -{{user-component/my-profile}} +{{user-component/my-profile user=user sendProfileImage=(action 'updateProfileImage')}} diff --git a/frontend/tests/unit/adapters/profile-image-test.js b/frontend/tests/unit/adapters/profile-image-test.js new file mode 100644 index 000000000..baebde8b2 --- /dev/null +++ b/frontend/tests/unit/adapters/profile-image-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Adapter | profile image', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:profile-image'); + assert.ok(adapter); + }); +}); diff --git a/frontend/tests/unit/controllers/my-profile-test.js b/frontend/tests/unit/controllers/my-profile-test.js new file mode 100644 index 000000000..d6e4998f9 --- /dev/null +++ b/frontend/tests/unit/controllers/my-profile-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | my-profile', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let controller = this.owner.lookup('controller:my-profile'); + assert.ok(controller); + }); +}); diff --git a/frontend/tests/unit/models/profile-image-test.js b/frontend/tests/unit/models/profile-image-test.js new file mode 100644 index 000000000..947b6a6f2 --- /dev/null +++ b/frontend/tests/unit/models/profile-image-test.js @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; + +module('Unit | Model | profile image', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let model = run(() => store.createRecord('profile-image', {})); + assert.ok(model); + }); +});