From f5e121d98ddae12123c6fc838afeff042b536f17 Mon Sep 17 00:00:00 2001 From: yackob03 Date: Tue, 1 Oct 2013 12:25:06 -0400 Subject: [PATCH 1/4] Fix user login from the command line. --- endpoints/index.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/endpoints/index.py b/endpoints/index.py index 2c2ca6e0a..4ecceeb99 100644 --- a/endpoints/index.py +++ b/endpoints/index.py @@ -44,11 +44,22 @@ def generate_headers(f): @app.route('/v1/users/', methods=['POST']) def create_user(): user_data = request.get_json() - new_user = model.create_user(user_data['username'], user_data['password'], - user_data['email']) - code = model.create_confirm_email_code(new_user) - send_confirmation_email(new_user.username, new_user.email, code.code) - return make_response('Created', 201) + username = user_data['username'] + password = user_data['password'] + + existing_user = model.get_user(username) + if existing_user: + verified = model.verify_user(username, password) + if verified: + return make_response('Verified', 201) + else: + abort(401) + else: + # New user case + new_user = model.create_user(username, password, user_data['email']) + code = model.create_confirm_email_code(new_user) + send_confirmation_email(new_user.username, new_user.email, code.code) + return make_response('Created', 201) @app.route('/v1/users', methods=['GET']) From e81a24a9ce494b4cd762e4da87dc8cb551305fa3 Mon Sep 17 00:00:00 2001 From: yackob03 Date: Tue, 1 Oct 2013 13:27:38 -0400 Subject: [PATCH 2/4] Move zeroclipboard and typeahead to the lib directory. --- static/js/controllers.js | 2 +- static/{js => lib}/ZeroClipboard.min.js | 0 static/{js => lib}/ZeroClipboard.swf | Bin static/{js => lib}/typeahead.min.js | 0 templates/index.html | 4 ++-- 5 files changed, 3 insertions(+), 3 deletions(-) rename static/{js => lib}/ZeroClipboard.min.js (100%) rename static/{js => lib}/ZeroClipboard.swf (100%) rename static/{js => lib}/typeahead.min.js (100%) diff --git a/static/js/controllers.js b/static/js/controllers.js index 43e0c57e3..d71a131cb 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -168,7 +168,7 @@ function RepoCtrl($scope, Restangular, $routeParams, $rootScope) { $scope.repo = repo; $scope.currentTag = repo.tags[tag] || repo.tags['latest']; - var clip = new ZeroClipboard($('#copyClipboard'), { 'moviePath': 'static/js/ZeroClipboard.swf' }); + var clip = new ZeroClipboard($('#copyClipboard'), { 'moviePath': 'static/lib/ZeroClipboard.swf' }); clip.on('complete', function() { // Resets the animation. var elem = $('#clipboardCopied')[0]; diff --git a/static/js/ZeroClipboard.min.js b/static/lib/ZeroClipboard.min.js similarity index 100% rename from static/js/ZeroClipboard.min.js rename to static/lib/ZeroClipboard.min.js diff --git a/static/js/ZeroClipboard.swf b/static/lib/ZeroClipboard.swf similarity index 100% rename from static/js/ZeroClipboard.swf rename to static/lib/ZeroClipboard.swf diff --git a/static/js/typeahead.min.js b/static/lib/typeahead.min.js similarity index 100% rename from static/js/typeahead.min.js rename to static/lib/typeahead.min.js diff --git a/templates/index.html b/templates/index.html index 3f2d6e08b..88c8e8fcb 100644 --- a/templates/index.html +++ b/templates/index.html @@ -24,8 +24,8 @@ - - + + From 4746f9c3246057a73ec2792338c5d2c8f2e03197 Mon Sep 17 00:00:00 2001 From: yackob03 Date: Tue, 1 Oct 2013 13:48:37 -0400 Subject: [PATCH 3/4] Quick fix for the signin page, we should consider moving it over to AJAX though. --- endpoints/web.py | 18 +++++++++++------- static/css/signin.css | 5 +++++ templates/signin.html | 6 +++++- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/endpoints/web.py b/endpoints/web.py index ca4f07c91..959b0fb8d 100644 --- a/endpoints/web.py +++ b/endpoints/web.py @@ -1,6 +1,7 @@ import logging -from flask import abort, send_file, redirect, request, url_for +from flask import (abort, send_file, redirect, request, url_for, + render_template) from flask.ext.login import login_user, UserMixin, login_required, logout_user from flask.ext.principal import identity_changed, Identity, AnonymousIdentity @@ -42,6 +43,11 @@ def common_login(db_user): identity_changed.send(app, identity=Identity(db_user.username, 'username')) +@app.route('/signin', methods=['GET']) +def render_signin_page(): + return render_template('signin.html') + + @app.route('/signin', methods=['POST']) def signin(): username = request.form['username'] @@ -54,7 +60,10 @@ def signin(): return redirect(request.args.get('next') or url_for('index')) - abort(403) + else: + return render_template('signin.html', + username=username, + error='Invalid username or password.') @app.route('/confirm', methods=['GET']) @@ -72,11 +81,6 @@ def password_reset(): pass -@app.route('/signin', methods=['GET']) -def render_signin_page(): - return send_file('templates/signin.html') - - @app.route("/signout") @login_required def logout(): diff --git a/static/css/signin.css b/static/css/signin.css index a6bf9b159..637ffdfb5 100644 --- a/static/css/signin.css +++ b/static/css/signin.css @@ -37,4 +37,9 @@ body { margin-bottom: 10px; border-top-left-radius: 0; border-top-right-radius: 0; +} + +.alert { + max-width: 300px; + margin: 0 auto; } \ No newline at end of file diff --git a/templates/signin.html b/templates/signin.html index 15051a495..20d9f2a38 100644 --- a/templates/signin.html +++ b/templates/signin.html @@ -10,10 +10,14 @@
+ + {% if error %} +
{{ error }}
+ {% endif %}
\ No newline at end of file From 96896b90673eef13e9548255d5fa2d4470c126ec Mon Sep 17 00:00:00 2001 From: yackob03 Date: Tue, 1 Oct 2013 14:14:39 -0400 Subject: [PATCH 4/4] Rename Image.image_id to Image.docker_image_id to reduce confusion. --- data/database.py | 4 ++-- data/model.py | 35 ++++++++++++++++++++++------------- endpoints/api.py | 2 +- endpoints/index.py | 6 +++--- endpoints/registry.py | 2 +- initdb.py | 4 ++++ test.db | Bin 40960 -> 40960 bytes 7 files changed, 33 insertions(+), 20 deletions(-) create mode 100644 initdb.py diff --git a/data/database.py b/data/database.py index 9400e0aa2..5ff37345c 100644 --- a/data/database.py +++ b/data/database.py @@ -86,7 +86,7 @@ class Image(BaseModel): # to be globally unique we can't treat them as such for permissions and # security reasons. So rather than Repository <-> Image being many to many # each image now belongs to exactly one repository. - image_id = CharField() + docker_image_id = CharField() checksum = CharField(null=True) created = DateTimeField(null=True) comment = TextField(null=True) @@ -99,7 +99,7 @@ class Image(BaseModel): database = db indexes = ( # we don't really want duplicates - (('repository', 'image_id'), True), + (('repository', 'docker_image_id'), True), ) diff --git a/data/model.py b/data/model.py index cc3646f03..2fc075669 100644 --- a/data/model.py +++ b/data/model.py @@ -182,25 +182,26 @@ def create_repository(namespace, name, owner): return repo -def create_image(image_id, repository): - new_image = Image.create(image_id=image_id, repository=repository) +def create_image(docker_image_id, repository): + new_image = Image.create(docker_image_id=docker_image_id, + repository=repository) return new_image -def set_image_checksum(image_id, repository, checksum): - fetched = Image.get(Image.image_id == image_id, +def set_image_checksum(docker_image_id, repository, checksum): + fetched = Image.get(Image.docker_image_id == docker_image_id, Image.repository == repository) fetched.checksum = checksum fetched.save() return fetched -def set_image_metadata(image_id, namespace_name, repository_name, +def set_image_metadata(docker_image_id, namespace_name, repository_name, created_date_str, comment, parent=None): joined = Image.select().join(Repository) image_list = list(joined.where(Repository.name == repository_name, Repository.namespace == namespace_name, - Image.image_id == image_id)) + Image.docker_image_id == docker_image_id)) if not image_list: raise DataModelException('No image with specified id and repository') @@ -232,9 +233,9 @@ def list_repository_tags(namespace_name, repository_name): def get_tag_image(namespace_name, repository_name, tag_name): joined = Image.select().join(RepositoryTag).join(Repository) - fetched = joined.where(Repository.name == repository_name, - Repository.namespace == namespace_name, - RepositoryTag.name == tag_name) + fetched = list(joined.where(Repository.name == repository_name, + Repository.namespace == namespace_name, + RepositoryTag.name == tag_name)) if not fetched: raise DataModelException('Unable to find image for tag.') @@ -242,8 +243,16 @@ def get_tag_image(namespace_name, repository_name, tag_name): return fetched[0] -def get_image_by_id(image_id): - return Image.get(Image.image_id == image_id) +def get_image_by_id(namespace_name, repository_name, docker_image_id): + joined = Image.select().join(Repository) + fetched = list(joined.where(Repository.name == repository_name, + Repository.namespace == namespace_name, + Image.docker_image_id == docker_image_id)) + + if not fetched: + raise DataModelException('Unable to find image for tag with repo.') + + return fetched[0] def get_parent_images(image_obj): @@ -259,10 +268,10 @@ def get_parent_images(image_obj): def create_or_update_tag(namespace_name, repository_name, tag_name, - tag_image_id): + tag_docker_image_id): repo = Repository.get(Repository.name == repository_name, Repository.namespace == namespace_name) - image = Image.get(Image.image_id == tag_image_id) + image = Image.get(Image.docker_image_id == tag_docker_image_id) try: tag = RepositoryTag.get(RepositoryTag.repository == repo, diff --git a/endpoints/api.py b/endpoints/api.py index 1f09d8b27..4896116d9 100644 --- a/endpoints/api.py +++ b/endpoints/api.py @@ -154,7 +154,7 @@ def delete_repository(namespace, repository): def image_view(image): return { - 'id': image.image_id, + 'id': image.docker_image_id, 'created': image.created, 'comment': image.comment, } diff --git a/endpoints/index.py b/endpoints/index.py index 4ecceeb99..4e146d254 100644 --- a/endpoints/index.py +++ b/endpoints/index.py @@ -123,8 +123,8 @@ def create_repository(namespace, repository): new_repo_images = {desc['id']: desc for desc in image_descriptions} added_images = dict(new_repo_images) for existing in model.get_repository_images(namespace, repository): - if existing.image_id in new_repo_images: - added_images.pop(existing.image_id) + if existing.docker_image_id in new_repo_images: + added_images.pop(existing.docker_image_id) else: existing.repositoryimage.delete() @@ -169,7 +169,7 @@ def get_repository_images(namespace, repository): all_images = [] for image in model.get_repository_images(namespace, repository): new_image_view = { - 'id': image.image_id, + 'id': image.docker_image_id, 'checksum': image.checksum, } all_images.append(new_image_view) diff --git a/endpoints/registry.py b/endpoints/registry.py index 830575d11..0fda2db78 100644 --- a/endpoints/registry.py +++ b/endpoints/registry.py @@ -291,7 +291,7 @@ def put_image_json(namespace, repository, image_id): # on a failed push # save the metadata if parent_id: - parent_obj = model.get_image_by_id(parent_id) + parent_obj = model.get_image_by_id(namespace, repository, parent_id) else: parent_obj = None diff --git a/initdb.py b/initdb.py new file mode 100644 index 000000000..d18a62084 --- /dev/null +++ b/initdb.py @@ -0,0 +1,4 @@ +from data.database import initialize_db + +if __name__ == '__main__': + initialize_db() \ No newline at end of file diff --git a/test.db b/test.db index de63aaddb19afeab70cc4994e163a6e246e00172..6041988e4597128ce412d425e6c9c520ab4819e0 100644 GIT binary patch delta 2085 zcmZWqeQZ-z6uvjiFoNG2@9W3Z`cL0I=iYOF z_x#T9oNhl#wjU)sufvJSij{l`4wLss{$QZs^_IKUmv0(39R&og5tK!UA&YyetikCN`y$Ifx;zyxN@#4Th6L zY9zWU(lC@xbcR|z(P(t2KcU51`h8mm`UbjI-I)LhepMv-*WAt z&UWL^rII8b!Egyq!4bpGy$lue!Gac4VU)joOV5_{<~~=VXKOE^ANtEHQ7N_{XSsy3 zIhh+)gb=`G41d5ixNO)LpM!-wU`!zMOW39)We>fJ;4HigKQOSvP&SWaPz6ZzqvejO zSsX+72cVb%SjhVbPQbIU0aQTb{VDx0p(j>|6HO}`)re223$KiKbSbgB33wE@*X34R zihGe;t#P|+v|zRBQ~a9W!&{IG8bTv0Lw-?4J!5Yn7t*EN%@p-sx zjOtz0*wGpFyTc7D+MC(~gk*3gW`J0b>Zw+|fq*aQVKkaRv2aHuLrSK~r); z|Bi8ctKFJMQx%1<7)h#&)U|X)BbwII77lxTKJ~xpD1jO^Sgon57El#dihvn%=gPMD zs;;ia6~Vh#dz-v1{|oUb)$F`m(@ZLPG>p(Nwbrkjj7io9Y_kMMRTbW`mTswkgl-P6 zGg6@g#C8z&!e_7p-huB}wFY6L3|zR7Y>VkEWRo|Yg>-SIvycujorU?5IpC5CGqNIs z#Lj_8EE!GlbUNuYxESHAXAt}fSKu2sW7yk2hPe_G9ua^?7)t~Ml3f_T#Ak6uafIUN z0v;z7 z??!A;zX2gwgLjhw@+Uq`ZX~Zx>El=k^H?v&K-X@o6|H$=KQpAfG0hAyZ=`qCiZe0e z6SblxzjJh=b{;>M!!Arb{^WW;YY)}01cREYakOMxcmb4ik_#8^kq|HG#S&e4<}yvzBkaE>lgh1_);;rP2{4y+##Le}hrago{RHH{0ab1f3jhEB delta 2098 zcmZuxZERCj7(VB`_xA3z-ACC*DL9#f7>0E1z3pwgIpfOKZev>qYd6+q0lTs9DZ)NL z2#hO6h-hSke4pHF$7R^FUpKNXVgy570+PItKeX7b}Uy zva&d~p?@&?Xn3W%DUw*#7wijlSCvFY8s)0k>d1!f&0%+^Kd{QLR(H2`mHNCJT02~^ z=EvC6+4CCOv4jdV(M8vFjSeR|2D?%_)@|-xF%T&k?u#`0>Y~FG16Kqm|2R4B-+(BR$3Kre!ZDV3%-y=Ov zV`(O5G?6n1&cMsi2Ra;aE*@xg4r$CZM=wkJDZ1^tcOU zwMeSMv`j*4&&?HgQW^|2#w$Y&u^8_p&?MIe?`+0hYLNJ4k5`u6*vRnFU}ZEOiZ-vTDUH-b zJ#FFEv=o1tS1D0spQ6f!kRs|usF#_m)|em9%aZJi7U7-i+19E(Y^pk+ZK-b3*M$xc z%X#<_cEXGB0ldYJZ#|6VffJ`|Z8E@gF+~GRS4%L!bUDBP(;Fta;H2p-nURfK04^Z7 z3BSXy@DqFs%+?;(3x(alrW>u)aG+oe`frUnf_WOj4YE4>0Ux~=sBu**FHyVjVk3lCiecC}}Y`4Zx{ z=PF!+A9Y*KImj~!MtOoHV19`JOajGNzcGM?BFZAFT;y83>AtXUAb_HBiglz0Gr@o}*R|W+;cKKYgOE5t$Hv znW~Ezei5*auuiOGBl&w$dmXd=BPS@GFWEzOtW`cYI*&a$8W8&)PV{uK^3g(AR#>E8 z9i4;cp1OTl-zBR)4`<;Nuk~$yVo{Nu-f9VwjO3#s83$)F2JzN8f)Q~gC{4DGClFZ; z%isvvPcFd_zD~071U@*aZNqoZ6|fV7;_vMC2l#dNyGu(|uWGIqv6hK}ofxZ_N0Vzv z`kD;ZK2|MBVUhBcEci-=WJ<*&`zs_d6))RfAqlCt{G|#BQt?ralaP^1*|~{|oJ{zJ zAN^4TpL2_zf}_0GH-UY)Gdq;YUFX1fFfrUUG%OJ_7EwN?#@i-viLLyf{8_mt9hlB8 z12bIX+g(KP2Y+gRfQ#HHp8%WLWiFDqIG7r#A~FPo