Skip to content

Commit 422174b

Browse files
committed
Major major update of UI and dependent features
* Introduced administration features * Added scss assets for css management using sass * Improved wares and users management * Updated tests
1 parent 4e15ea7 commit 422174b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1712
-343
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ FLUIDHUB_DATAPATH=./_dev/server/data docker-compose -f docker/docker-compose.yml
106106
## Run tests
107107

108108

109-
Run the [nosetests](http://nose.readthedocs.io) tool from the root of the source tree, using the `dev-runtests wrapper` script:
109+
Run the [nosetests](http://nose.readthedocs.io) tool from the root of the source tree, using the `dev-runtests` wrapper script:
110110
```
111111
./dev-runtests nosetests
112112
```

dev-buildtests

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env sh
22

3-
CWDIR="$(dirname "$(readlink -f "$0")")"
3+
CWDIR=$(cd "$(dirname "$0")"; pwd)
44

55
FLUIDHUB_DATAPATH=${CWDIR}/_dev/server/data docker-compose \
66
-f docker/docker-compose.yml \

dev-runtests

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env sh
22

3-
CWDIR="$(dirname "$(readlink -f "$0")")"
3+
CWDIR=$(cd "$(dirname "$0")"; pwd)
44

55
FLUIDHUB_DATAPATH=${CWDIR}/_dev/server/data docker-compose \
66
-f docker/docker-compose.yml \

dev-server

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env sh
22

3-
CWDIR="$(dirname "$(readlink -f "$0")")"
3+
CWDIR=$(cd "$(dirname "$0")"; pwd)
44

55
FLUIDHUB_DATAPATH=${CWDIR}/_dev/server/data docker-compose \
66
-f docker/docker-compose.yml \

fluidhub/FluidHub/GitInfosReader.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import os
77

88
from FluidHub.WaresOperations import WaresOperations
9-
from FluidHub.ConfigManager import ConfigMan #TODO is this necessary?
9+
from FluidHub.ConfigManager import ConfigMan #REVIEW is this necessary?
1010

1111

1212
################################################################################

fluidhub/FluidHub/Tools.py

+43
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import os
77
import errno
8+
import re
89

910

1011
################################################################################
@@ -31,3 +32,45 @@ def noneToEmptyString(Data):
3132
Ret[Key] = ""
3233

3334
return Ret
35+
36+
37+
################################################################################
38+
39+
40+
def isValidUsername(Username) :
41+
return re.match("^[a-z][a-z0-9]*$", Username)
42+
43+
44+
################################################################################
45+
46+
47+
def isValidEmail(Email) :
48+
return re.match("^[\w.\-_]*\@\w[\w.\-_]*$", Email)
49+
50+
51+
################################################################################
52+
53+
54+
def isValidEmail(Email) :
55+
return re.match("^[\w.\-_]*\@\w[\w.\-_]*$", Email)
56+
57+
58+
################################################################################
59+
60+
61+
def getAsValidList(Str,ValidFunc,WildcardOK=False,Sep=","):
62+
Lst = Str.split(Sep)
63+
ValidLst = list()
64+
65+
for Item in Lst:
66+
Item = Item.strip(" ")
67+
68+
if (WildcardOK and Item == "*") :
69+
ValidLst.append(Item)
70+
elif Item:
71+
if ValidFunc(Item):
72+
ValidLst.append(Item)
73+
else:
74+
return None
75+
76+
return ValidLst

fluidhub/FluidHub/UsersManager.py

+29-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
from sqlalchemy import create_engine, MetaData, Table
77
import bcrypt
8-
import re
98

109
from FluidHub import Tools
1110

@@ -82,8 +81,8 @@ def getUser(self,Username) :
8281

8382
def createUser(self, Username, Definition) :
8483
# check valid chars for username (A-Z,a-z,0-9,.,_, must start with an alphabetic char)
85-
if not re.match("^[a-z][a-z0-9_-]*$", Username):
86-
return 400,"invalid username"
84+
if not Tools.isValidUsername(Username):
85+
return 400,"invalid username format"
8786

8887
# check if provided json data is correct
8988
if not all(name in Definition for name in ("username","password")) :
@@ -94,6 +93,8 @@ def createUser(self, Username, Definition) :
9493

9594
if "email" not in Definition.keys() :
9695
Definition["email"] = ""
96+
elif not Tools.isValidEmail(Definition["email"]):
97+
return 400,"invalid email format"
9798

9899
if "fullname" not in Definition.keys() :
99100
Definition["fullname"] = ""
@@ -120,8 +121,14 @@ def createUser(self, Username, Definition) :
120121

121122

122123
def updateUser(self, Username, Definition) :
123-
# TODO
124-
return 501,""
124+
125+
if "fullname" in Definition:
126+
self.Users.update().where(self.Users.c.username == Username).values(fullname=Definition["fullname"]).execute()
127+
128+
if "email" in Definition:
129+
self.Users.update().where(self.Users.c.username == Username).values(email=Definition["email"]).execute()
130+
131+
return 200,""
125132

126133

127134
################################################################################
@@ -144,9 +151,23 @@ def deleteUser(self, Username) :
144151
################################################################################
145152

146153

147-
def changePassword(self, Username, OldPassword, NewPassword) :
148-
# TODO
149-
return False
154+
def changePassword(self, Username, NewPassword) :
155+
156+
Salt = bcrypt.gensalt()
157+
HashedPassword = bcrypt.hashpw(NewPassword.encode('utf8'), Salt)
158+
159+
self.Users.update().where(self.Users.c.username == Username).values(password=HashedPassword).execute()
160+
161+
return 200,""
162+
163+
164+
################################################################################
165+
166+
167+
@staticmethod
168+
def isAdmin(Username) :
169+
return Username == "admin"
170+
150171

151172

152173
################################################################################

fluidhub/FluidHub/WaresOperations.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -180,18 +180,29 @@ def createWare(self,Type,ID,Definition) :
180180

181181
def updateWare(self,Type,ID,Definition) :
182182

183-
# TODO implement updating ware
184-
185183
WareGitPath = self.getWareGitReposPath(Type,ID)
186184
WareDefPath = self.getWaresDefsPath(Type)
187185
WareDefFile = self.getWareDefFilePath(Type,ID)
188186

189187
if not os.path.exists(WareGitPath) or not os.path.isfile(WareDefFile) :
190188
return 404,"does not exists"
191189

192-
return 501,"not implemented"
190+
with open(WareDefFile, 'r') as DefFileR:
191+
Data = json.load(DefFileR)
192+
DefFileR.close()
193193

194-
return 200,""
194+
DefKeys = Definition.keys()
195+
for Key in ["shortdesc","users-ro","users-rw","mailinglist"] :
196+
if Key in DefKeys:
197+
Data[Key] = Definition[Key]
198+
199+
# writing the updated definition
200+
with open(WareDefFile, 'w') as DefFileW:
201+
json.dump(Data, DefFileW, indent=2)
202+
203+
return 200,""
204+
205+
return 500,"error in existing definition file"
195206

196207

197208
################################################################################

fluidhub/app/api/users.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
__author__ = "Jean-Christophe Fabre <jean-christophe.fabre@inra.fr>"
44

55

6-
from flask import Blueprint,jsonify,request,g
6+
from flask import Blueprint,jsonify,request,g,abort
77

88
from FluidHub import Constants
99
from FluidHub.UsersManager import UsersMan
@@ -49,7 +49,7 @@ def GetUser(username) :
4949
@tokenAuth.login_required
5050
def CreateUser(username) :
5151

52-
if g.username != "admin":
52+
if not UsersMan.isAdmin(g.username):
5353
abort(403)
5454

5555
Data = request.get_json(silent=True)
@@ -66,7 +66,7 @@ def CreateUser(username) :
6666
@tokenAuth.login_required
6767
def UpdateUser(username) :
6868

69-
if g.username != "admin":
69+
if not UsersMan.isAdmin(g.username):
7070
abort(403)
7171

7272
abort(501)
@@ -79,7 +79,7 @@ def UpdateUser(username) :
7979
@tokenAuth.login_required
8080
def DeleteUser(username) :
8181

82-
if g.username != "admin":
82+
if not UsersMan.isAdmin(g.username):
8383
abort(403)
8484

8585
Code,Res = UsersMan.deleteUser(username)

fluidhub/app/api/wares.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
__author__ = "Jean-Christophe Fabre <jean-christophe.fabre@inra.fr>"
44

55

6-
from flask import Blueprint,jsonify,request,g
6+
from flask import Blueprint,jsonify,request,g,abort
77

88
from FluidHub import Constants
99
from FluidHub.WaresOperations import WaresOperations
1010
from FluidHub.RoutesAuth import tokenAuth
11+
from FluidHub.UsersManager import UsersManager
1112

1213

1314
################################################################################
@@ -66,15 +67,15 @@ def GetWare(ware_type,ware_id) :
6667
@tokenAuth.login_required
6768
def CreateWare(ware_type,ware_id) :
6869

69-
if g.username != "admin":
70+
if not UsersManager.isAdmin(g.username):
7071
abort(403)
7172

7273
if ware_type not in Constants.WareTypes :
7374
return "invalid ware type",404
7475

7576
WaresOps = WaresOperations()
7677

77-
# TODO is method check necessary
78+
# REVIEW is method check necessary
7879
if request.method == 'PUT' :
7980
Code,Data = WaresOps.createWare(ware_type,ware_id,request.get_json(silent=True))
8081
return Data,Code
@@ -87,15 +88,15 @@ def CreateWare(ware_type,ware_id) :
8788
@tokenAuth.login_required
8889
def UpdateWare(ware_type,ware_id) :
8990

90-
if g.username != "admin":
91+
if not UsersManager.isAdmin(g.username):
9192
abort(403)
9293

9394
if ware_type not in Constants.WareTypes :
9495
return "invalid ware type",404
9596

9697
WaresOps = WaresOperations()
9798

98-
# TODO is method check necessary
99+
# REVIEW is method check necessary
99100
if request.method == 'PATCH' :
100101
Code,Data = WaresOps.updateWare(ware_type,ware_id,request.get_json(silent=True))
101102
return Data,Code
@@ -108,15 +109,15 @@ def UpdateWare(ware_type,ware_id) :
108109
@tokenAuth.login_required
109110
def DeleteWare(ware_type,ware_id) :
110111

111-
if g.username != "admin":
112+
if not UsersManager.isAdmin(g.username):
112113
abort(403)
113114

114115
if ware_type not in Constants.WareTypes :
115116
return "invalid ware type",404
116117

117118
WaresOps = WaresOperations()
118119

119-
# TODO is method check necessary
120+
# REVIEW is method check necessary
120121
if request.method == 'DELETE' :
121122
Code,Data = WaresOps.deleteWare(ware_type,ware_id)
122123
return Data,Code

fluidhub/app/main.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
@app.route("/")
4242
def Root():
43-
return redirect(url_for('ui.Root'))
43+
return redirect(url_for('ui.Home'))
4444

4545

4646

0 commit comments

Comments
 (0)