diff --git a/config/dev.config.ts b/config/dev.config.ts index f6428b5c8910b10978e135b7e06c95abdae2e4fa..3c265c8693e2892a1ac57a389b23a24ebcbbcc8a 100644 --- a/config/dev.config.ts +++ b/config/dev.config.ts @@ -1,5 +1,3 @@ -import { Headers } from 'angular2/http'; - export class config { public static SERVICES:any = { "app": {"url": "http://127.0.0.1:5400"}, @@ -7,8 +5,9 @@ export class config { "project": {"url": "http://127.0.0.1:5402"}, "document": {"url": "http://127.0.0.1:5403"} }; - public static HEADERS = new Headers({ + public static HEADERS:any = { 'x-blocpower-app-key': '$APP_KEY' - }); + }; + public static google_client_id:string = '$GOOGLE_CLIENT_ID'; public static static_url:string = '/current'; }; diff --git a/config/production.config.ts b/config/production.config.ts index 9e99a36ba584c1cdfd44e9ad6089b1f5d7c6f99b..7f59d76241a0e82c8a8dd23ff8d8831609ddd4de 100644 --- a/config/production.config.ts +++ b/config/production.config.ts @@ -1,13 +1,12 @@ -import { Headers } from 'angular2/http'; - export class config { public static SERVICES:any = { "user": {"url": "http://user.s.blocpower.us"}, "project": {"url": "http://project.s.blocpower.us"}, "document": {"url": "http://document.s.blocpower.us"} }; - public static HEADERS = new Headers({ + public static HEADERS = { 'x-blocpower-app-key': '$APP_KEY' - }); + }; + public static google_client_id:string = '$GOOGLE_CLIENT_ID'; public static static_url:string = '$CURRENT'; }; diff --git a/config/staging.config.ts b/config/staging.config.ts index d8a54a4d0b9fdaee56ea9a66d394260c5ee3ea5b..c097f5ef946329c84e52a88855526d6199998986 100644 --- a/config/staging.config.ts +++ b/config/staging.config.ts @@ -1,13 +1,12 @@ -import { Headers } from 'angular2/http'; - export class config { public static SERVICES:any = { "user": {"url": "http://staging.user.s.blocpower.us"}, "project": {"url": "http://staging.project.s.blocpower.us"}, "document": {"url": "http://staging.document.s.blocpower.us"} }; - public static HEADERS = new Headers({ + public static HEADERS = { 'x-blocpower-app-key': '$APP_KEY' - }); + }; + public static google_client_id:string = '$GOOGLE_CLIENT_ID'; public static static_url:string = '$CURRENT'; }; diff --git a/front/current/assets/fontello/config.json b/front/current/assets/fontello/config.json index 7785853b5c100944ec924f21be18cfa98f9a0a2a..cc781f7f365c917a122baa6dbc9a2be92d034a20 100644 --- a/front/current/assets/fontello/config.json +++ b/front/current/assets/fontello/config.json @@ -71,6 +71,12 @@ "css": "upload", "code": 59402, "src": "fontawesome" + }, + { + "uid": "0d20938846444af8deb1920dc85a29fb", + "css": "logout", + "code": 59403, + "src": "fontawesome" } ] } \ No newline at end of file diff --git a/front/current/assets/fontello/css/blocpower-codes.css b/front/current/assets/fontello/css/blocpower-codes.css index d35dd5d01fb7199e9b3be32228b87e9f643bd492..0edfa21cddcdb642f975d6af0406c4c88b2487a6 100644 --- a/front/current/assets/fontello/css/blocpower-codes.css +++ b/front/current/assets/fontello/css/blocpower-codes.css @@ -9,4 +9,5 @@ .icon-mobile:before { content: '\e807'; } /* '' */ .icon-envelope:before { content: '\e808'; } /* '' */ .icon-fax:before { content: '\e809'; } /* '' */ -.icon-upload:before { content: '\e80a'; } /* '' */ \ No newline at end of file +.icon-upload:before { content: '\e80a'; } /* '' */ +.icon-logout:before { content: '\e80b'; } /* '' */ \ No newline at end of file diff --git a/front/current/assets/fontello/css/blocpower-embedded.css b/front/current/assets/fontello/css/blocpower-embedded.css index 64bac37b1bb9a52c1a75b141bef8be0284cc3f50..3f71918a1b9c650a91d5b24e724fd3ad4082d728 100644 --- a/front/current/assets/fontello/css/blocpower-embedded.css +++ b/front/current/assets/fontello/css/blocpower-embedded.css @@ -1,15 +1,15 @@ @font-face { font-family: 'blocpower'; - src: url('../font/blocpower.eot?944541'); - src: url('../font/blocpower.eot?944541#iefix') format('embedded-opentype'), - url('../font/blocpower.svg?944541#blocpower') format('svg'); + src: url('../font/blocpower.eot?50626490'); + src: url('../font/blocpower.eot?50626490#iefix') format('embedded-opentype'), + url('../font/blocpower.svg?50626490#blocpower') format('svg'); font-weight: normal; font-style: normal; } @font-face { font-family: 'blocpower'; - src: url('data:application/octet-stream;base64,d09GRgABAAAAABNUAA8AAAAAH5gAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADMAAABCsP6z7U9TLzIAAAGMAAAAQwAAAFY+IEj4Y21hcAAAAdAAAAB5AAAB/Old3VNjdnQgAAACTAAAABMAAAAgBtX/BGZwZ20AAAJgAAAFkAAAC3CKkZBZZ2FzcAAAB/AAAAAIAAAACAAAABBnbHlmAAAH+AAACDYAAAu43gM5dWhlYWQAABAwAAAAMgAAADYJh9onaGhlYQAAEGQAAAAfAAAAJAc9A1lobXR4AAAQhAAAACQAAAAwKHj/9mxvY2EAABCoAAAAGgAAABoRhA7cbWF4cAAAEMQAAAAgAAAAIAF/DHluYW1lAAAQ5AAAAYUAAALZ2Vl9rHBvc3QAABJsAAAAaQAAAIjvdibXcHJlcAAAEtgAAAB6AAAAhuVBK7x4nGNgZGBg4GKQY9BhYHRx8wlh4GBgYYAAkAxjTmZ6IlAMygPKsYBpDiBmg4gCAIojA08AeJxjYGSOZ5zAwMrAwFTFtIeBgaEHQjM+YDBkZAKKMrAyM2AFAWmuKQwOLxhecDEH/c9iiGIOYpgGFGYEyQEA3rELlgB4nO2RwRHCQAwD94gJIUcpvCmIFwVRpLtIZKMy8MxqxhrfPSTgCiziKQLGh0HNW+5of2FvP3j1TZSf+3FIKdUerRfdhn5cubFx17spe+U/j9avt1nJ/egsjfIjTXWSptJNU32lUc6kUeKkUfakUQukqR7TME8HeR1dAAAAeJxjYEADEhDIHPQ/C4QBEmwD3QB4nK1WaXfTRhQdeUmchCwlCy1qYcTEabBGJmzBgAlBsmMgXZytlaCLFDvpvvGJ3+Bf82Tac+g3flrvGy8kkLTncJqTo3fnzdXM22USWpLYC+uRlJsvxdTWJo3sPAnphk3LUXwoO3shZYrJ3wVREK2W2rcdh0REIlC1rrBEEPseWZpkfOhRRsu2pFdNyi096S5b40G9Vd9+GjrKsTuhpGYzdGg9siVVGFWiSKY9UtKmZaj6K0krvL/CzFfNUMKITiJpvBnG0EjeG2e0ymg1tuMoimyy3ChSJJrhQRR5lNUS5+SKCQzKB82Q8sqnEeXD/Iis2KOcVrBLttP8vi95p3c5P7Ffb1G25EAfyI7s4Ox0JV+EW1th3LST7ShUEXbXd0Js2exU/2aP8ppGA7crMr3QjGCpfIUQKz+hzP4hWS2cT/mSR6NaspETQetlTuxLPoHW44gpcc0YWdDd0QkR1P2SMwz2mD4e/PHeKZYLEwJ4HMt6RyWcCBMpYXM0SdowcmAlZYsqqfWumDjldVrEW8J+7drRl85o41B3YjxbDx1bOVHJ8WhSp5lMndpJzaMpDaKUdCZ4zK8DKD+iSV5tYzWJlUfTOGbGhEQiAi3cS1NBLDuxpCkEzaMZvbkbprl2LVqkyQP13KP39OZWuLnTU9oO9LNGf1anYjrYC9PpaeQv8Wna5SJF6frpGX5M4kHWAjKRLTbDlIMHb/0O0svXlhyF1wbY7u3zK6h91kTwpAH7G9AeT9UpCUyFmFWIVkBirWtZlsnVrBapyNR3Q5pWvqzTBIpyHBfHvoxx/V8zM5aYEr7fidOzIy49c+1LCNMcfJt1PZrXqcVyAXFmeU6nWZbv6zTH8gOd5lme1+kIS1unoyw/1GmB5Uc6HWN5QQuadN/BkIsw5AIOkDCEpQNDWF6CISwVDGG5CENYFmEIyyUYwvJjGMJyGYawvKxl1dRTSePamVgGbEJgYo4eucxF5WoquVRCu2hUakOeEm6VVBTPqn9loF488oY5sBZIl8iaXzHOlY9G5fjWFS1vGjtXwLHqbx+O9jnxUtaLhT8F/9XWVCW9Ys3Dk6vwG4aebCeqNql4dE2Xz1U9uv5fVFRYC/QbSIVYKMqybHBnIoSPOp2GaqCVQ8xszDy063XLmp/D/TcxQhZQ/fg3FBoL3INOWUlZ7eCs1dfbstw7g3I4EyxJMTfz+lb4IiOz0n6RWcqej3wecAWMSmXYagOtFbzZJzEPmd4kzwRxW1E2SNrYzgSJDRzzgHnznQQmYeqqDeRO4YYN+AVhbsF5J1yieqMsh+5F7PMopPxbp+JE9qhojMCz2Rthr+9Cym9xDCQ0+aV+DFQVoakYNRXQNFJuqAZfxtm6bULGDvQjKnbDsqziw8cW95WSbRmEfKSI1aOjn9Zeok6q3H5mFJfvnb4FwSA1MX9733RxkMq7WskyR20DU7calVPXmkPjVYfq5lH1vePsEzlrmm66Jx56X9Oq28HFXCyw9m0O0lImF9T1YYUNosvFpVDqZTRJ77gHGBYY0O9Qio3/q/rYfJ4rVYXRcSTfTtS30edgDPwP2H9H9QPQ92Pocg0uz/eaE59u9OFsma6iF+un6Dcwa625WboG3NB0A+IhR62OuMoNfKcGcXqkuRzpIeBj3RXiAcAmgMXgE921jOZTAKP5jDk+wOfMYdBkDoMt5jDYZs4awA5zGOwyh8Eecxh8wZx1gC+ZwyBkDoOIOQyeMCcAeMocBl8xh8HXzGHwDXPuA3zLHAYxcxgkzGGwr+nWMMwtXtBdoLZBVaADU09Y3MPiUFNlyP6OF4b9vUHM/sEgpv6o6faQ+hMvDPVng5j6i0FM/VXTnSH1N14Y6u8GMfUPg5j6TL8Yy2UGv4x8lwoHlF1sPufvifcP28VAuQABAAH//wAPeJy1Vm9sW1cVv+fe9+57fnb99/k9J7FfHMd+duMsaexnu03bxE2bNlHTLk3TLm23NPTP/jkJ7dgo0A1prQYrhAy60pVOIBWGYLB9aCa0whCptGpM1ZCqCiFE0QTdlzIkPiGxSYvLuc9h67SNLwjbOu+ed+7zu/ec3+93LmGE3H6P3aILRCUJ0kV6ql0tQKAzQimhWwiaIwQIgXECQCYYhsiI5km3N8c8CS0hyXo+UyamQRVuR1I8qpuGH+ysY5ccUiyYii0bUd0PeeiCSrnkZMsVOJuCB/2+P1qFl+Z/eovSeC5JKaSuD/VtzsHYN6S4LhnNlI5y/8JqeFPlS38p7z4E1+uXrKBhYVRNazdhdXi31Hf+bdtulpK6P3n2i/4MIYTjXt5nt5iXBEgr6Sb95G6yn6yrrvGCogFnCp/yAFOBAqNTMrjbwgvuS3L3Nblv987tW0vLn6JPTuQzUZ0r7Sk7W3LKZrFghNDPLvsV9EHE25bjbQ0/Dw1/LTT87HK8gvEI+u3LflHMt5LGgmkBWiN5x5BeTRpLf3M9aprWUuWzY/Ax7/y0gcPotJEEC3hNXMyaiNZ/d0eEpmvidcLU37pjEqgf3sd80ttLtx9mf2djJEtGyfbq1rTBGdCRAYdJDMEBlGEqZxRgEmVSjSBkJjhm1TdEJEmeILK8Qh5emQOyZbCnOze6clQP+zSShayKsIGUwvGrG61QLJTKFfxiPk2F4w2jD7oRMQFEkg2pqJjH21NZO1sp291g+6EVN9cPhmkUC+LBioO34R8nj85sHJRlSRqPyKXiznsO3j3v9Hqo719eXZN6adizYdPee6HoBncfHB0aLK1Vqfe95ahW3bT3vvtPHJ0dcP+DjVX7arNPqh4K4QM7d3T39K1e44mwAvMYwXdUL1+32c7VpUYoaX0yJp4+oaoURB5vYx4vsBXIsTaSr+ZaEXN+wFRuIRKCUCJTCD+RyynM4Qo6bLbrkbAsN+XB6QJuQR+AzlPdgEnoon2SRU1dQc6dPPPWWWn+93OQ6uzVFw8dHz39YJWum55/Ye7Iaja4GIUTD5ymZ6+e43P184mO6OJg38Pf/uH8bK80cP/ZbccPLUaxxrg8NJN0B4kSs6oLggNWlsDn8f79ZhOVjTzoATANNDyVBdupQLmANYJJfuMG53HZz+sfcA6SHJTinKYU+c83uB/vyyDhFQ2OUUga3BRY6iebqhtyADyEVKx0UYm2AWYck0FlKskzRGZUZjVcBZWAThHUKEbuJZz7+HBvS6ZUzhQVuSUPy1wqhRrcSoDrcyWkG8jF8npocDAS0rnAh8igWH3WbnCPhSc31ldtnJzcCKcUTVPqxzIOlNNwLeNoalrV/mDEvQfqZ+Sg3I/bmz6o6UFIBHQYWXCfuTYwCe48J1Nf5T65oGoa/Kn+TsCgnoP1M5z3i/1PH/DGDcNNM+LgfRZGfRol6Wrb5gIKn9ikSyVMOIqtm/WBalvSZnI0n9GXod+FfLCzXbh0wQscVxxEfR8yxzRMhINFUWWpogtelCwwC4JElUIfrRQsJAsSxcTt+rh3jVMMxtPq2nJ+6FxnS0RTVUlhkGiN+1cFVEnTua4rNKgmbQtJDf6O2REIy16uaJaV9CnBGN0Q8WUZ/UFglT+ejEsai+otneeG8uW4GQwn/QHHWePlPspyWs4K0FhQ9aaaU6qsepkB22Y7fFhXsHIWqEGa8fKIJom8SAIb8DJ9HfkRQ4b0kIFqf1jzMEZF18H0KESSFWmKII6Y3EAEMMEaLIzoTHyCcOAjJafHsTORsCrH8xnHTvkxHeVKyLEFLKIICyx7mTmoPToCoxL6CD+uFrNmO0bjKesRTa3fFIgAS/FNe/Z48HehM16/mejoSICV6KhGmt2pNXgaS67WvyQK/1dPOLx0RUyh69CSBu8vYm99nTSRMrmr2uHBWjOkF6MMqw1Y7Y9aq6DiSKlgp3uLkuBcqNFYKiHDLTE2mz5wtU5gIgB+mnVhQV1YLAP6lpP54Gq6DE2tV0eS9qYWGh/Ite5/NRkrr7zulHyppJf6rLS39OxUuH0ddOVZOe3AG/XBBu5fi0dPVWLNcWiOm5seNxY7RxOn27OesA80Xc0eHvCbY+l8r4P67uqZ4HIA2VwhW8g95AFyjHydPEd+Ql4ll8lL1ReDECMXX3zyyzuGuUe98L2jD21Ygwv/zqnP7elZyV22GyYeHMhME5CYSWK1ZoghhlVPTJ2KBii+lnLFw6ciK6gS1Gij/qbJJghjvqGQl6K+TFDs3itg+NIlIJcuX7q8+JvXfvmLV17++Y9/9P3nv/vst7751Mknjj/2hZna4YP37du1c9vWwY3r15aKd+XbrCbDwwlmsQU7UaRgIDbctl0RUiIjgUIflxbBKxNKjo2TOOqMgfAR+vJf/cj/eX6lhAeR9dAWupBxnMwQ1t3JsKGkDeNr61bGsUw4ZjqhXQED6oc1dYtA6meYZzR1SOB9SPifHImw63+6Ke0xkvXn6ePl9JK7Erof8bQvMpCtj68dxyXtwZOFEdwVKBtLT3z42uc+ZVR/938Jv/2MZe6t30TeMTy3XGT7UWdNkkY1GakOS0gxQTyJSIzMCNmVCGCHkSWQa0RRQWKuvnAuj+O5ReiJzEeaYt1dK3OtVizdlDb09jaPHMsDz//nkLcesABOf6MdspSfWoAk7aKAJ17RqAHFlx6RfTVNraka/vgC98uvqL/dOTdKx5/+2dd2S9vnYd8jb9x6c5Z/5df//NVX4SHvFbGfK1qAL8jyggeax+ZemBtzTf3aY1ceffTKu8L8G7lf9iEAAHicY2BkYGAAYgvBhZnx/DZfGbiZXwBFGC47eDvD6P9//2cxv2YOAnI5GJhAogA3zgvfAAB4nGNgZGBgDvqfBSRf/P/7/xfzawagCArgAQC2SAebAHicY37BwMAMx///Mi/4/58xFcoXBLLXgMX/g3Hk/78AqLoUhAAAAAAAZgEOAbICAAI0ArYDQgOuBBoFagXcAAAAAQAAAAwAwQAMAAAAAAACADYARgBzAAAAvQtwAAAAAHicdZDNTsJAFIXPAGKQxAUmrmejwZiUH6MLF4aEADsXLGBdytAWS6eZDhpWvoXv4AO59Vk8LRNi/GnT2++ee3vvmQJo4RMC++uWz54FGsz2XMExHhxXqY8c18iPjo/QxNxxnfrC8Qmu8eS4iTO8cYKoNZit8e5YoCXOHFdwKi4cV6nfOK6RR46PcC7mjuvUN45PMBOvjpu4FB9Dne1MHEZWtodXst/t3cnFTmpKceon0t/aSJtcDuRKp1YlifYCvVkkOsj0izJTFW4T3xzyA8yUyWOdyp7XPWgTlSrjW7UsNuTPYd/alVwZvZFjN1tmRq9VYL3I2uy+0/m+E0NoZNjBIEaICBYSbapXfPfRRQ93pAU7JDv3XTFS+Eio+Njyi6is5MwHfFbMUqqKHQnZQ8C44YwiC7hN44VVgyljyAkJ55g/6r+VWRlzOih2SLrz6PF334QxLckvnSwPZ8jxzJ19qpZOC7emdCcx/uFbcl5RW1MJqHvl37FU79Hh/c85vwBil4gFAAAAeJxtwUESgjAMBdB8KG1FPIqHihKgY0w7tDgc34Vb36OOfkb6b0KHHg4DPAIiLhhxxYQbDSsfqzhNtYVakpnsvgrvz82pLC1qstddzhY2trlK8+/8SCpR7COai/QLn/4omnkm+gJQORtRAAAAeJxj8N7BcCIoYiMjY1/kBsadHAwcDMkFGxlYnTYxMDJogRibuZgYOSAsPgYwi81pF9MBoDQnkM3utIvBAcJmZnDZqMLYERixwaEjYiNzistGNRBvF0cDAyOLQ0dySARISSQQbOZhYuTR2sH4v3UDS+9GJgYXAAx2I/QAAA==') format('woff'), - url('data:application/octet-stream;base64,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') format('truetype'); + src: url('data:application/octet-stream;base64,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') format('woff'), + url('data:application/octet-stream;base64,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') format('truetype'); } /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ @@ -17,7 +17,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'blocpower'; - src: url('../font/blocpower.svg?944541#blocpower') format('svg'); + src: url('../font/blocpower.svg?50626490#blocpower') format('svg'); } } */ @@ -62,4 +62,5 @@ .icon-mobile:before { content: '\e807'; } /* '' */ .icon-envelope:before { content: '\e808'; } /* '' */ .icon-fax:before { content: '\e809'; } /* '' */ -.icon-upload:before { content: '\e80a'; } /* '' */ \ No newline at end of file +.icon-upload:before { content: '\e80a'; } /* '' */ +.icon-logout:before { content: '\e80b'; } /* '' */ \ No newline at end of file diff --git a/front/current/assets/fontello/css/blocpower-ie7-codes.css b/front/current/assets/fontello/css/blocpower-ie7-codes.css index 52046ba21b34ec4b38b2aaab0b6ea33aef19ae3d..b2b831abe21ef225c14bf8a875f633e51e47746c 100644 --- a/front/current/assets/fontello/css/blocpower-ie7-codes.css +++ b/front/current/assets/fontello/css/blocpower-ie7-codes.css @@ -9,4 +9,5 @@ .icon-mobile { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-envelope { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-fax { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-upload { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } \ No newline at end of file +.icon-upload { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } \ No newline at end of file diff --git a/front/current/assets/fontello/css/blocpower-ie7.css b/front/current/assets/fontello/css/blocpower-ie7.css index f8e2262b4c6e3f540c4dc140163107fef54f8a5c..a05f7f254efff979f58a3a51e3c067dc62409e85 100644 --- a/front/current/assets/fontello/css/blocpower-ie7.css +++ b/front/current/assets/fontello/css/blocpower-ie7.css @@ -20,4 +20,5 @@ .icon-mobile { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-envelope { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-fax { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-upload { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } \ No newline at end of file +.icon-upload { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } \ No newline at end of file diff --git a/front/current/assets/fontello/css/blocpower.css b/front/current/assets/fontello/css/blocpower.css index c7554454375fcd2748e9412d4b70fb024c6f1034..8eedef58be54ad865f922c29f1bdae3eea86cb50 100644 --- a/front/current/assets/fontello/css/blocpower.css +++ b/front/current/assets/fontello/css/blocpower.css @@ -1,11 +1,11 @@ @font-face { font-family: 'blocpower'; - src: url('../font/blocpower.eot?52046343'); - src: url('../font/blocpower.eot?52046343#iefix') format('embedded-opentype'), - url('../font/blocpower.woff2?52046343') format('woff2'), - url('../font/blocpower.woff?52046343') format('woff'), - url('../font/blocpower.ttf?52046343') format('truetype'), - url('../font/blocpower.svg?52046343#blocpower') format('svg'); + src: url('../font/blocpower.eot?31577778'); + src: url('../font/blocpower.eot?31577778#iefix') format('embedded-opentype'), + url('../font/blocpower.woff2?31577778') format('woff2'), + url('../font/blocpower.woff?31577778') format('woff'), + url('../font/blocpower.ttf?31577778') format('truetype'), + url('../font/blocpower.svg?31577778#blocpower') format('svg'); font-weight: normal; font-style: normal; } @@ -15,7 +15,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'blocpower'; - src: url('../font/blocpower.svg?52046343#blocpower') format('svg'); + src: url('../font/blocpower.svg?31577778#blocpower') format('svg'); } } */ @@ -65,4 +65,5 @@ .icon-mobile:before { content: '\e807'; } /* '' */ .icon-envelope:before { content: '\e808'; } /* '' */ .icon-fax:before { content: '\e809'; } /* '' */ -.icon-upload:before { content: '\e80a'; } /* '' */ \ No newline at end of file +.icon-upload:before { content: '\e80a'; } /* '' */ +.icon-logout:before { content: '\e80b'; } /* '' */ \ No newline at end of file diff --git a/front/current/assets/fontello/font/blocpower.eot b/front/current/assets/fontello/font/blocpower.eot index 38c80942c5fed9690229a7e7769c0519e2194646..aec6e8f23da566135a3a75a1528c0f3eef252d39 100644 Binary files a/front/current/assets/fontello/font/blocpower.eot and b/front/current/assets/fontello/font/blocpower.eot differ diff --git a/front/current/assets/fontello/font/blocpower.svg b/front/current/assets/fontello/font/blocpower.svg index 5bbd3fb9437d07361c0a363d79682bbc7fe584d8..33f0ab2c25fddd02127e6556f69cbfd0b81fcee7 100644 --- a/front/current/assets/fontello/font/blocpower.svg +++ b/front/current/assets/fontello/font/blocpower.svg @@ -27,6 +27,8 @@ + + \ No newline at end of file diff --git a/front/current/assets/fontello/font/blocpower.ttf b/front/current/assets/fontello/font/blocpower.ttf index 6473b344e6e8f02df119bb36d8eb8145e9a03003..ebe78f244e2b786af45cedab5108b41b198983db 100644 Binary files a/front/current/assets/fontello/font/blocpower.ttf and b/front/current/assets/fontello/font/blocpower.ttf differ diff --git a/front/current/assets/fontello/font/blocpower.woff b/front/current/assets/fontello/font/blocpower.woff index e7244bcc25a1078ad263198bf58ccb0ff2efbf32..2ac1d49132233dca15168d6d58218397bf26e470 100644 Binary files a/front/current/assets/fontello/font/blocpower.woff and b/front/current/assets/fontello/font/blocpower.woff differ diff --git a/front/current/assets/fontello/font/blocpower.woff2 b/front/current/assets/fontello/font/blocpower.woff2 index 76bbea9abca85683a65482596f2805a980c7317c..29f8beb00cf52a263b7657b5e312adc765d5d139 100644 Binary files a/front/current/assets/fontello/font/blocpower.woff2 and b/front/current/assets/fontello/font/blocpower.woff2 differ diff --git a/front/current/assets/styles/components/_global.scss b/front/current/assets/styles/components/_global.scss index 900bc13b5782866d06ba22aa8a680282a5eafcb6..2a470360a5c36ce8ded8a7f40eddc64086c76383 100644 --- a/front/current/assets/styles/components/_global.scss +++ b/front/current/assets/styles/components/_global.scss @@ -37,7 +37,7 @@ body { } my-app { - display: block; + display: flex; height: 100%; } @@ -127,3 +127,10 @@ input[type=file].hidden { } .float-right { display: inline; float: right; } + +.fullscreen { + margin: auto 0; + vertical-align: middle; + text-align: center; + flex-grow: 1; +} diff --git a/front/current/assets/styles/components/_login.scss b/front/current/assets/styles/components/_login.scss new file mode 100644 index 0000000000000000000000000000000000000000..c69371d12173c05cdfaece3ecf24688f9a2b9c84 --- /dev/null +++ b/front/current/assets/styles/components/_login.scss @@ -0,0 +1,9 @@ +login { + flex-grow: 1; + margin: auto 0; + text-align: center; + + #google-login { + display: inline-block; + } +} diff --git a/front/current/assets/styles/components/_nav.scss b/front/current/assets/styles/components/_nav.scss index d4d220eb3b8092be912167fd5e4e4b14e89f530e..70f244d8c8f44a8c947af93f3628ba6e4305e4c3 100644 --- a/front/current/assets/styles/components/_nav.scss +++ b/front/current/assets/styles/components/_nav.scss @@ -1,39 +1,49 @@ -nav.vertical { - background-color: $gray-01; - width: 50px; - height: 100%; - float: left; +navigation-bar { + flex-basis: 50px; - ul { - margin: 0; + nav.vertical { + background-color: $gray-01; - li { - display: block; - list-style: none; + ul { + margin: 0; + display: flex; + flex-direction: column; + height: 100%; - a { - display: block; - padding: 14px; - color: inherit; - &:visited { - color: inherit; - } - &:active { + li { + list-style: none; + flex-basis: 50px; + line-height: 50px; + vertical-align: middle; + text-align: center; + height: 50px; + + a { color: inherit; + &:visited { + color: inherit; + } + &:active { + color: inherit; + } + &:hover { + color: inherit; + } + &.logo { + img { + width: 35px; + margin: 7px; + } + } } - &:hover { - color: inherit; + &.current { + background: $white; } - &.logo { - padding: 7px; - img { - width: 35px; - } + &.spacer { + flex-grow: 1; + flex-basis: auto; } } - &.current { - background: $white; - } } } } diff --git a/front/current/assets/styles/components/_project-list.scss b/front/current/assets/styles/components/_project-list.scss index 872144688af769ad055ab7578a8598b3c8003908..0e17541cd8d2958cffbeb26b0084f135ada8984b 100644 --- a/front/current/assets/styles/components/_project-list.scss +++ b/front/current/assets/styles/components/_project-list.scss @@ -1,44 +1,47 @@ -div.projects { - width: calc(100% - 60px); // TODO Replace this with something more global. - margin-left: 60px; - padding: 10px 0; +project-list { + flex-grow: 1; - table { + div.projects { width: 100%; - font-size: .9em; + padding: 10px; - th.project-state, td.project-state { - width: 150px; - } - - tr { - border-bottom: 1px solid $light-gray; + table { + width: 100%; + font-size: .9em; - th, td { - line-height: 1.5em; - padding: 5px; + th.project-state, td.project-state { + width: 150px; } - th { - text-transform: uppercase; - font-weight: normal; - text-align: left; - color: $gray-02; - } - td { - text-align: left; - vertical-align: top; + + tr { + border-bottom: 1px solid $light-gray; + + th, td { + line-height: 1.5em; + padding: 5px; + } + th { + text-transform: uppercase; + font-weight: normal; + text-align: left; + color: $gray-02; + } + td { + text-align: left; + vertical-align: top; + } } - } - tbody { - tr:last-child { - border-bottom: none; + tbody { + tr:last-child { + border-bottom: none; + } } - } - ul.document-list { - li { - list-style: none; + ul.document-list { + li { + list-style: none; + } } } } diff --git a/front/current/assets/styles/components/_project.scss b/front/current/assets/styles/components/_project.scss index 413adc92d9a888ed444c65dd52dadc08ad345634..29ee3e60214636cae32f115c53526e4323c06d05 100644 --- a/front/current/assets/styles/components/_project.scss +++ b/front/current/assets/styles/components/_project.scss @@ -8,14 +8,14 @@ project { display: flex; flex-direction: column; - margin-left: 50px; - height: 100%; + flex-grow: 1; header { display: flex; border-bottom: 1px solid $light-gray; - flex-basis: 300px; + flex-basis: 200px; flex-grow: 0; + flex-shrink: 0; .project-details, .project-contacts { padding: 10px; } .project-details { diff --git a/front/current/assets/styles/styles.scss b/front/current/assets/styles/styles.scss index 791c60fe31a549b0ef80a565af610c9f16ff52a1..81aec0fb3d2b33ed5bf515d7d03c677fedc15884 100644 --- a/front/current/assets/styles/styles.scss +++ b/front/current/assets/styles/styles.scss @@ -8,6 +8,7 @@ @import 'components/animation'; @import 'components/button'; @import 'components/nav'; +@import 'components/login'; @import 'components/project'; @import 'components/project-list'; @import 'components/loaders'; diff --git a/front/current/components/app/app.component.ts b/front/current/components/app/app.component.ts index 5db938caab06a3ad427620e98f0d0f86d59b6ae7..77db73ddd60fea1076537bf17ce956fc7818afdc 100644 --- a/front/current/components/app/app.component.ts +++ b/front/current/components/app/app.component.ts @@ -1,6 +1,5 @@ import { Component } from 'angular2/core'; - -import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from 'angular2/router'; +import { RouteConfig, ROUTER_PROVIDERS, RouterLink } from 'angular2/router'; import { config } from '../../config'; @@ -12,9 +11,14 @@ import { ContactMethodService } from '../../services/project/contact-method.serv import { DocumentSlotService } from '../../services/project/document-slot.service'; import { DocumentService } from '../../services/document/document.service'; +import { GoogleService } from '../../services/google.service'; + +import { GoogleLoginRouterOutlet } from '../../directives/google-login.directive'; + import { NavComponent } from '../nav/nav.component'; import { ProjectListComponent } from '../projects/list.component'; import { ProjectDetailComponent } from '../project/detail.component' +import { LoginComponent } from '../login/login.component'; @Component({ @@ -22,12 +26,15 @@ import { ProjectDetailComponent } from '../project/detail.component' templateUrl: config.static_url + '/components/app/app.component.html', providers: [ ROUTER_PROVIDERS, + RestService, ProjectService, AddressService, ContactService, ContactMethodService, DocumentSlotService, - DocumentService + DocumentService, + + GoogleService ], - directives: [ROUTER_DIRECTIVES, NavComponent] + directives: [GoogleLoginRouterOutlet, NavComponent] }) @RouteConfig([ { @@ -37,9 +44,14 @@ import { ProjectDetailComponent } from '../project/detail.component' useAsDefault: true }, { - path: '/project/:id/:section', + path: '/project/:id', name: 'Project', component: ProjectDetailComponent + }, + { + path: '/login', + name: 'Login', + component: LoginComponent } ]) export class AppComponent { diff --git a/front/current/components/login/login.component.html b/front/current/components/login/login.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c352e269c6d021135413ae67c46e1083756d7468 --- /dev/null +++ b/front/current/components/login/login.component.html @@ -0,0 +1 @@ +
diff --git a/front/current/components/login/login.component.ts b/front/current/components/login/login.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..8416f9aadfd8d9625be38f820e007f37c900703a --- /dev/null +++ b/front/current/components/login/login.component.ts @@ -0,0 +1,37 @@ +import { Component, OnInit } from 'angular2/core'; +import { Router, RouteParams } from 'angular2/router'; +import { config } from '../../config'; +import { GoogleService } from '../../services/google.service'; + + +@Component({ + selector: 'login', + templateUrl: config.static_url + '/components/login/login.component.html' +}) +export class LoginComponent implements OnInit { + constructor ( + public googleService:GoogleService, + public router:Router, + public routeParams:RouteParams + ) {}; + + ngOnInit() { + let self = this; + let next = self.routeParams.get('next'); + next = (next ? decodeURIComponent(next) : '/'); + + self.googleService.render(); + self.googleService.onLogIn(() => { + // router.navigateByURL is the right way to do this, but causes an error + // where google attempts to grab the removed login button. This causes + // the googleService to crash and thus doesn't execute the onInit of the + // next component in the instruction set. + // + // As a workaround, we circumvent angular routing and just navigate to + // the next url. + // + //self.router.navigateByUrl(next); + window.location.href = next; + }); + }; +}; diff --git a/front/current/components/nav/nav.component.html b/front/current/components/nav/nav.component.html index 164369f9cfdde5a50fca5cd96c06f28eed1d5514..85b3a3fa4d9c66bf1e939823c2969943ad60995d 100644 --- a/front/current/components/nav/nav.component.html +++ b/front/current/components/nav/nav.component.html @@ -1,12 +1,12 @@ diff --git a/front/current/components/nav/nav.component.ts b/front/current/components/nav/nav.component.ts index 8e57ad5422d29ca02b54934ab43df2592321795f..6856d2334a071839b9d59b8e1bacb995a40460bc 100644 --- a/front/current/components/nav/nav.component.ts +++ b/front/current/components/nav/nav.component.ts @@ -1,13 +1,25 @@ import { Component } from 'angular2/core'; -import { ROUTER_DIRECTIVES } from 'angular2/router'; +import { Router, RouterLink } from 'angular2/router'; + import { config } from '../../config'; +import { GoogleService } from '../../services/google.service'; @Component({ selector: 'navigation-bar', templateUrl: config.static_url + '/components/nav/nav.component.html', - directives: [ROUTER_DIRECTIVES] + directives: [RouterLink] }) export class NavComponent { + constructor( + public googleService:GoogleService, + public router:Router + ) {} + public config:any = config; + + public logOut() { + this.googleService.logOut(); + this.router.navigate(['Login']); + }; }; diff --git a/front/current/components/projects/list.component.html b/front/current/components/projects/list.component.html index 9a992665b8855812fcf82980dcf213b958ceb9cd..299f2b4059b9f149900d2dabf4da97598763a7cc 100644 --- a/front/current/components/projects/list.component.html +++ b/front/current/components/projects/list.component.html @@ -29,7 +29,7 @@ {{ project.data['name'] }} diff --git a/front/current/components/projects/list.component.ts b/front/current/components/projects/list.component.ts index 92780f7d10ed8b8e447d8389b0c747739af5610a..835c628e1ac7280c56ce3132b945a3c233d846c7 100644 --- a/front/current/components/projects/list.component.ts +++ b/front/current/components/projects/list.component.ts @@ -6,6 +6,7 @@ import { config } from '../../config'; import { RestService, Model, Collection } from '../../services/rest.service'; import { ProjectService } from '../../services/project/project.service'; + @Component({ selector: 'project-list', templateUrl: config.static_url + '/components/projects/list.component.html', diff --git a/front/current/directives/google-login.directive.ts b/front/current/directives/google-login.directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d031a4c4da06749628b0890834b1b0c47dc9994 --- /dev/null +++ b/front/current/directives/google-login.directive.ts @@ -0,0 +1,32 @@ +import { ElementRef, DynamicComponentLoader, Attribute, Directive } from 'angular2/core'; +import { Router, RouterOutlet, ComponentInstruction } from 'angular2/router'; +import { GoogleService } from '../services/google.service'; + + +@Directive({ + selector: 'router-outlet' +}) +export class GoogleLoginRouterOutlet extends RouterOutlet { + constructor( + _elementRef:ElementRef, _loader:DynamicComponentLoader, + public router:Router, @Attribute('name') nameAttr:string, + public googleService:GoogleService + ) { + super(_elementRef, _loader, router, nameAttr); + } + + activate(instruction:ComponentInstruction) { + let url; + + if (this._canActivate(instruction.urlPath)) { + return super.activate(instruction); + } + + url = '/' + instruction.urlPath + '?' + instruction.urlParams.join('&'); + this.router.navigate(['Login', {next: encodeURIComponent(url)}]); + } + + private _canActivate(url) { + return url == 'login' || this.googleService.isLoggedIn(); + } +} diff --git a/front/current/lib/cache.ts b/front/current/lib/cache.ts new file mode 100644 index 0000000000000000000000000000000000000000..9110b35330304725b7f0f08341193b41459d112f --- /dev/null +++ b/front/current/lib/cache.ts @@ -0,0 +1,30 @@ +import { extend } from './object'; + + +class Cache { + // A wrapper around local storage. + public get(key:string):any { + return localStorage.getItem(key); + }; + public set(key:string, value:any):any { + return localStorage.setItem(key, value); + }; + public remove(key:string):any { + return localStorage.removeItem(key); + }; + + public getObject(key:string):any { + // JSON.parse's an object from local storage. + return JSON.parse(this.get(key)) || {}; + }; + public setObject(key:string, value:any):any { + // JSON.stringify's an object into local storage. + return this.set(key, JSON.stringify(value)); + }; + public updateObject(key:string, value:any):any { + // Update an object in local storage. + let object = this.getObject(key) || {}; + return this.setObject(key, extend(object, value)); + }; +}; +export default new Cache(); diff --git a/front/current/services/document/document.service.ts b/front/current/services/document/document.service.ts index 3850b181560a6207a7fc80462fc38bfab3a7244e..524591c270d56bbd9fe7988ed0373607b21ea6f8 100644 --- a/front/current/services/document/document.service.ts +++ b/front/current/services/document/document.service.ts @@ -3,6 +3,7 @@ import { config } from '../../config'; @Injectable() export class DocumentService { + public service_name:string = 'document'; public config:any = config.SERVICES.document; public url:string = '/document/'; }; diff --git a/front/current/services/google.service.ts b/front/current/services/google.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..fbb5a2d65f816843634a02ec04f0b650c0a1bbb5 --- /dev/null +++ b/front/current/services/google.service.ts @@ -0,0 +1,63 @@ +import { Injectable } from 'angular2/core'; +import { config } from '../config'; +import cache from '../lib/cache'; + + +declare var gapi:any; + + +@Injectable() +export class GoogleService { + public auth2:any; + public user:any; // Google user, not blocpower user. + public google_token:string; + private login_listeners:any[] = []; + + constructor() { + let self = this; + self.google_token = cache.get('x-blocpower-google-token') + gapi.load('auth2', function() { + let auth2 = self.auth2 = gapi.auth2.init({ + client_id: config.google_client_id, + hosted_domain: 'blocpower.org' + }); + auth2.currentUser.listen(self.change.bind(self)); // User change + }); + }; + + public render() { + gapi.signin2.render('google-login', {'scope': 'email'}); + }; + + public change(user:any) { + let old_token = this.google_token; + + this.user = user; + if (user) + this.google_token = user.getAuthResponse().id_token; + else + this.google_token = undefined; + cache.set('x-blocpower-google-token', this.google_token); + + if (!old_token && this.google_token) { + while (this.login_listeners.length) + this.login_listeners.pop()(); + } + }; + + public logOut() { + this.change(undefined); + this.auth2.disconnect(); + + cache.remove('x-blocpower-auth-key'); + cache.remove('x-blocpower-auth-token'); + }; + + public onLogIn(f) { + this.login_listeners.push(f); + }; + + public isLoggedIn() { + return this.google_token && this.google_token !== 'undefined'; + }; +}; diff --git a/front/current/services/project/address.service.ts b/front/current/services/project/address.service.ts index 3aece4a94ecfee5fb8dbb4251da33e46fd683e10..6157031c94af8cd586afe3cfdbb1fc01a2bbb98e 100644 --- a/front/current/services/project/address.service.ts +++ b/front/current/services/project/address.service.ts @@ -4,6 +4,7 @@ import { config } from '../../config'; @Injectable() export class AddressService { + public service_name:string = 'project'; public config:any = config.SERVICES.project; public url:string = '/address/'; }; diff --git a/front/current/services/project/contact-method.service.ts b/front/current/services/project/contact-method.service.ts index be12ed10d13c5479bf69f88a4f70f0acc574534b..c2691acc18f7b233c7240219ab13861adf68d12d 100644 --- a/front/current/services/project/contact-method.service.ts +++ b/front/current/services/project/contact-method.service.ts @@ -4,6 +4,7 @@ import { Model } from '../rest.service'; @Injectable() export class ContactMethodService { + public service_name:string = 'project'; public config:any = config.SERVICES.project; public url:string = '/contact/method/'; diff --git a/front/current/services/project/contact.service.ts b/front/current/services/project/contact.service.ts index 4271bc2da7a19a3e21836dc4dfe0ab831e04f959..e50ac2b9f8a48e438e8d2f91e0c2a0226e9896bd 100644 --- a/front/current/services/project/contact.service.ts +++ b/front/current/services/project/contact.service.ts @@ -3,6 +3,7 @@ import { config } from '../../config'; @Injectable() export class ContactService { + public service_name:string = 'project'; public config:any = config.SERVICES.project; public url:string = '/contact/'; }; diff --git a/front/current/services/project/document-slot.service.ts b/front/current/services/project/document-slot.service.ts index 8f0960f7773f2c690af3cfc35aff40c7d5520d02..960d1f555c919f9930207568ab43e11752e91d29 100644 --- a/front/current/services/project/document-slot.service.ts +++ b/front/current/services/project/document-slot.service.ts @@ -3,6 +3,7 @@ import { config } from '../../config'; @Injectable() export class DocumentSlotService { + public service_name:string = 'project'; public config:any = config.SERVICES.project; public url:string = '/project/document/'; }; diff --git a/front/current/services/project/project.service.ts b/front/current/services/project/project.service.ts index b8d395b88ca6bc4ec9bd67762ec0478891fda80a..0db2072e1fc636440d174d9a7f6484071eeb2cd2 100644 --- a/front/current/services/project/project.service.ts +++ b/front/current/services/project/project.service.ts @@ -4,6 +4,7 @@ import { Model } from '../rest.service'; @Injectable() export class ProjectService { + public service_name:string = 'project'; public config:any = config.SERVICES.project; public url:string = '/project/'; diff --git a/front/current/services/rest.service.ts b/front/current/services/rest.service.ts index 68db1334998efe6f6e8db6001ad396f5903e5c06..a0222984862cdb662555e91748695aae8e9f35a5 100644 --- a/front/current/services/rest.service.ts +++ b/front/current/services/rest.service.ts @@ -1,11 +1,13 @@ import { Injectable } from 'angular2/core'; -import { Http, Response, URLSearchParams } from 'angular2/http'; +import { Http, Response, Headers } from 'angular2/http'; import { Observable } from 'rxjs/Observable'; import { config } from '../config'; import { extend } from '../lib/object'; +import cache from '../lib/cache'; import { param } from '../lib/url'; + export class Model { constructor( public service:any, @@ -32,7 +34,28 @@ export class Model { return this; }; - get url(): string { + get headers():any { + let headers = extend({}, config.HEADERS); + + let token = cache.getObject('app_tokens')[this.service.service_name]; + if (token) + headers['x-blocpower-app-token'] = token; + + for ( + let h of [ + 'x-blocpower-google-token', + 'x-blocpower-auth-key', + 'x-blocpower-auth-token' + ] + ) { + let t = cache.get(h); + if (t) + headers[h] = t; + }; + + return new Headers(headers); + }; + get url():string { return ( this.service.config.url + this.service.url + @@ -41,6 +64,18 @@ export class Model { }; parse(response:Response):Model { + // Update the model and metadata from the response. + + // Set the app token in the cache. + let app_tokens = cache.getObject('app_tokens'); + app_tokens[this.service.service_name] = response.headers.get('x-blocpower-app-token'); + cache.setObject('app_tokens', app_tokens); + + // Set headers in the cache. + for (let h of ['x-blocpower-auth-key', 'x-blocpower-auth-token']) { + cache.set(h, response.headers.get(h)); + }; + return this.set(response.json().data); }; setError(response:Response) { @@ -52,7 +87,7 @@ export class Model { let self = this; self.loading = true; self.error = undefined; - return (self._http.get(self.url, {headers: config.HEADERS}) + return (self._http.get(self.url, {headers: self.headers}) .do(self.parse.bind(self), self.setError.bind(self), () => { self.loading = false; }) .subscribe(observer)); }; @@ -66,14 +101,14 @@ export class Model { self._http[method]( self.url, JSON.stringify(self.data), - {headers: config.HEADERS} + {headers: self.headers} ) .do(self.parse.bind(self), self.setError.bind(self), () => { self.loading = false; }) .subscribe(observer)); }; destroy():Observable { // Delete a model on the server. - return this._http.delete(this.url, {headers: config.HEADERS}); + return this._http.delete(this.url, {headers: this.headers}); }; }; @@ -111,11 +146,44 @@ export class Collection { return this; }; - public get url(): string { + get headers():any { + let headers = extend({}, config.HEADERS); + + let token = cache.getObject('app_tokens')[this.service.service_name]; + if (token) + headers['x-blocpower-app-token'] = token; + + for ( + let h of [ + 'x-blocpower-google-token', + 'x-blocpower-auth-key', + 'x-blocpower-auth-token' + ] + ) { + let t = cache.get(h); + if (t) + headers[h] = t; + }; + + return new Headers(headers); + }; + get url():string { return this.service.config.url + this.service.url + param(this.filters); }; parse(response:Response):Collection { + // Update the model and metadata from the response. + + // Set the app token in the cache. + let app_tokens = cache.getObject('app_tokens'); + app_tokens[this.service.service_name] = response.headers.get('x-blocpower-app-token'); + cache.setObject('app_tokens', app_tokens); + + // Set headers in the cache. + for (let h of ['x-blocpower-auth-key', 'x-blocpower-auth-token']) { + cache.set(h, response.headers.get(h)); + }; + return this.set(response.json().data); }; setError(response:Response) { @@ -127,7 +195,7 @@ export class Collection { let self = this; self.loading = true; self.error = undefined; - return (self._http.get(self.url, {headers: config.HEADERS}) + return (self._http.get(self.url, {headers: self.headers}) .do(self.parse.bind(self), self.setError.bind(self), () => { self.loading = false; }) .subscribe(observer)); }; diff --git a/front/index.default.html b/front/index.default.html index a5c6978964f20742a1cf1000e3bc98724bfd801d..9280e52da27b1ab278b4b93a76beec5563f0967e 100644 --- a/front/index.default.html +++ b/front/index.default.html @@ -21,6 +21,8 @@ + +