diff --git a/server/extensions.py b/server/extensions.py index 1ef41774..cbf82369 100644 --- a/server/extensions.py +++ b/server/extensions.py @@ -35,12 +35,12 @@ Base = declarative_base() Base.metadata.reflect(engine) else: - logging.warning("Testing mode, using local sqlite db.") + logging.warning("Testing mode, using local sqlite test db.") engine = create_engine( - "sqlite:///" + os.path.join(basedir, "openml.db"), + "sqlite:///" + os.path.join(basedir, "openml.test.db"), echo=False, ) - Config.SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(basedir, "openml.db") + Config.SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(basedir, "openml.test.db") Base = declarative_base() Base.metadata.reflect(engine) diff --git a/server/openml.test.db b/server/openml.test.db new file mode 100644 index 00000000..aa20b071 Binary files /dev/null and b/server/openml.test.db differ diff --git a/server/public/views.py b/server/public/views.py index e9e6dd48..50088464 100644 --- a/server/public/views.py +++ b/server/public/views.py @@ -22,8 +22,8 @@ CORS(blueprint) -DO_SEND_EMAIL = strtobool(os.environ.get("SEND_EMAIL", "True")) - +def email_enabled(): + return strtobool(os.getenv("SEND_EMAIL", "True")) @blueprint.route("/signup", methods=["POST"]) def signupfunc(): @@ -45,7 +45,7 @@ def signupfunc(): user.remember_code = "0000" user.created_on = "0000" user.last_login = "0000" - user.active = "0" if DO_SEND_EMAIL else "1" + user.active = "0" if email_enabled() else "1" user.first_name = register_obj["first_name"] user.last_name = register_obj["last_name"] user.company = "0000" @@ -59,7 +59,7 @@ def signupfunc(): user.password_hash = "0000" token = secrets.token_hex() user.update_activation_code(token) - if DO_SEND_EMAIL: + if email_enabled(): confirmation_email(user.email, token) session.add(user) session.commit() @@ -81,7 +81,7 @@ def password(): token = secrets.token_hex() user.update_forgotten_code(token) # user.update_forgotten_time(timestamp) - if DO_SEND_EMAIL: + if email_enabled(): forgot_password_email(user.email, token) session.merge(user) session.commit() @@ -100,7 +100,7 @@ def confirmation_token(): return jsonify({"msg": "User confirmation token sent"}), 200 token = secrets.token_hex() user.update_activation_code(token) - if DO_SEND_EMAIL: + if email_enabled(): confirmation_email(user.email, token) # updating user groups here user_group = UserGroups(user_id=user.id, group_id=2) diff --git a/server/src/client/app/src/pages/auth/APIKey.js b/server/src/client/app/src/pages/auth/APIKey.js index ac65cdde..e799c7db 100644 --- a/server/src/client/app/src/pages/auth/APIKey.js +++ b/server/src/client/app/src/pages/auth/APIKey.js @@ -46,8 +46,8 @@ function APIKey() { const [apikey, setApikey] = useState(''); const yourConfig = { headers: { - Authorization: "Bearer " + localStorage.getItem("token"), - }, + Authorization: "Bearer " + localStorage.getItem("token") + } }; useEffect(() => { @@ -66,7 +66,7 @@ function APIKey() { axios .post( process.env.REACT_APP_URL_SITE_BACKEND + "api-key", - { resetapikey: true }, + {}, // no form data required yourConfig ) .then((response) => { diff --git a/server/src/client/app/src/pages/auth/ProfilePage.js b/server/src/client/app/src/pages/auth/ProfilePage.js index 713e7ab0..a050d3f3 100755 --- a/server/src/client/app/src/pages/auth/ProfilePage.js +++ b/server/src/client/app/src/pages/auth/ProfilePage.js @@ -92,14 +92,16 @@ function Public() { setFname(response.data.first_name); setLname(response.data.last_name); setId(response.data.id); - if (id !== false) { + if (id) { fetch(`${ELASTICSEARCH_SERVER}user/user/` + id.toString()) .then(response => response.json()) .then(data => { - setDataset(data._source.datasets_uploaded); - setRun(data._source.runs_uploaded); - setTask(data._source.tasks_uploaded); - setFlow(data._source.flows_uploaded); + if (data._source) { + setDataset(data._source.datasets_uploaded); + setRun(data._source.runs_uploaded); + setTask(data._source.tasks_uploaded); + setFlow(data._source.flows_uploaded); + } }); } }) diff --git a/server/src/client/app/src/pages/auth/SignIn.js b/server/src/client/app/src/pages/auth/SignIn.js index 7f5f17ea..fa5a8221 100755 --- a/server/src/client/app/src/pages/auth/SignIn.js +++ b/server/src/client/app/src/pages/auth/SignIn.js @@ -33,8 +33,7 @@ function SignIn() { const [errorlog, setError] = useState(false); const [confirmflag, setConfirm] = useState(false); const [errormsg, setErrorMsg] = useState(false); - const [notexist, setNotExist] = useState(false); - const [wrongpass, setWrongPass] = useState(false); + const [incorrectCredentials, setIncorrectCredentials] = useState(false); const context = useContext(MainContext); function sendtoflask(event) { @@ -46,12 +45,10 @@ function SignIn() { }) .then(response => { console.log(response.data); - if (response.data.msg === "NotConfirmed") { + if (response.data.msg === "UserNotConfirmed") { setConfirm(true); - } else if (response.data.msg === "Wrong username or password") { - setNotExist(true); - } else if (response.data.msg === "wrong password") { - setWrongPass(true); + } else if (response.data.msg === "WrongUsernameOrPassword") { + setIncorrectCredentials(true); } else { localStorage.setItem("token", response.data.access_token); context.checkLogIn(); @@ -75,12 +72,15 @@ function SignIn() { )} + {/** Header **/} Welcome back! Sign in to continue + + {/** Start Error Banner **/} {errorlog && ( )} - {wrongpass && ( + {/* User with this email & password could not be found */} + {(incorrectCredentials) && ( )} + {/* User's account not yet confirmed */} {confirmflag && ( (resend activation token) )} - {notexist && ( - - - Wrong username or password - - )} + {/** End Error Banner **/} + + {/** Start Entry Fields **/}
Email Address @@ -156,6 +152,7 @@ function SignIn() { Forgot password + {/** End Entry Fields **/}
diff --git a/server/src/client/app/src/pages/auth/SignUp.js b/server/src/client/app/src/pages/auth/SignUp.js index 56d596ab..4454c1db 100755 --- a/server/src/client/app/src/pages/auth/SignUp.js +++ b/server/src/client/app/src/pages/auth/SignUp.js @@ -7,12 +7,18 @@ import { useState } from "react"; import { FormControl, + IconButton, Input, InputLabel, + InputAdornment, Button as MuiButton, Paper, Typography } from "@mui/material"; +import { + Visibility, + VisibilityOff +} from '@mui/icons-material'; import { spacing } from "@mui/system"; import axios from "axios"; @@ -30,53 +36,84 @@ const RedIcon = styled(FontAwesomeIcon)({ color: red[500] }); +const MIN_PASSWORD_LENGTH = 15; + function SignUp() { const [register, setRegister] = useState(false); const [duplicateUser, setDuplicateUser] = useState(false); const [error, setError] = useState(false); const [errormessage, setErrorMessage] = useState(false); - function sendflask(event) { + + const [firstName, setFirstName] = useState(""); + const [lastName, setLastName] = useState(""); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + + const [showPassword, setShowPassword] = useState(false); + + function handleSubmit(event) { event.preventDefault(); - console.log(event.target.email.value); - console.log(event.target.password.value); - if (event.target.password.value.length < 8) { + var registrationData = { + email: email, + firstName: firstName, + lastName: lastName, + password: password + }; + + if (password.length < MIN_PASSWORD_LENGTH) { + // Password must meet minimum length + // Using NIST recommendation setError(true); - setErrorMessage("Password too weak. Use at least 8 characters, with numbers, digits, and special characters."); - } else if ( - /[a-zA-Z0-9]+@(?:[a-zA-Z0-9-]+\.)+[A-Za-z]+$/.test( - event.target.email.value - ) !== true - ) { + setErrorMessage(`Password too weak. Use at least ${MIN_PASSWORD_LENGTH} characters.`); + } else if ( (/[a-zA-Z0-9]+@(?:[a-zA-Z0-9-]+\.)+[A-Za-z]+$/.test(email)) === false) { + // Email must be in valid format setError(true); setErrorMessage("Please enter valid email"); } else { - axios - .post(process.env.REACT_APP_URL_SITE_BACKEND + "signup", { - first_name: event.target.fname.value, - last_name: event.target.lname.value, - email: event.target.email.value, - password: event.target.password.value - }) - .then(function(response) { - if (response.data.msg === "User created") { - console.log(response.data); - setRegister(true); - } else if (response.data.msg === "User already exists") { - setDuplicateUser(true); - } - }) - .catch(function(error) { - console.log(error.data); - }); + sendflask(registrationData); } + return false; } + + function handleMouseDownPassword(event) { + event.preventDefault(); // Prevents focus loss + } + + function handleClickShowPassword() { + setShowPassword(function(prev) { + return !prev; + }); + } + + function sendflask(registrationData) { + axios + .post(process.env.REACT_APP_URL_SITE_BACKEND + "signup", { + first_name: registrationData.firstName, + last_name: registrationData.lastName, + email: registrationData.email, + password: registrationData.password + }) + .then(function(response) { + if (response.data.msg === "User created") { + console.log(response.data); + setRegister(true); + } else if (response.data.msg === "User alredy exists") { + setDuplicateUser(true); + } + }) + .catch(function(error) { + console.log(error.data); + }) + } + return ( Almost there -
+ + {/* Error Banner */} {duplicateUser && ( User already exists @@ -87,31 +124,64 @@ function SignUp() { {errormessage} )} + + {/* Input fields */} First name - + Last name - + Email Address (we never share your email) - + - Password (min 8 characters) + Password (min {MIN_PASSWORD_LENGTH} characters) + + {showPassword ? : } + + + } /> +