Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: extract homepage and repository and description from fpm.toml #36

Merged
merged 75 commits into from
Jun 25, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
fc97933
feat: add APIs for email verification
henilp105 May 11, 2023
7a24e58
feat: add UI for email verification
henilp105 May 11, 2023
47079db
feat: add reducers and actions for email verification
henilp105 May 11, 2023
de8a8be
fix: redundant variable
henilp105 May 11, 2023
1093191
feat: add APIs for email change functionality
henilp105 May 11, 2023
d3b1b6e
feat: fix bugs
henilp105 May 11, 2023
815699c
fix: #34
henilp105 May 16, 2023
5ba8f05
add readme for the registry
henilp105 May 16, 2023
f904731
add: help and fix rreducers
henilp105 May 16, 2023
c96154a
fix: #35
henilp105 May 16, 2023
d6fa8e0
token duration
henilp105 May 16, 2023
0024731
add the read description and homepage and repository
henilp105 May 16, 2023
f4ddeb8
nfeat: update packages
henilp105 May 16, 2023
2cac330
add : css to help page
henilp105 May 16, 2023
2d8152f
Merge branch 'fortran-lang:main' into main
henilp105 May 16, 2023
7050da2
update: readme
henilp105 May 16, 2023
7a41c6b
Merge branch 'main' of https://github.com/henilp105/registry
henilp105 May 16, 2023
ed56575
fix: fix admin page bugs
henilp105 May 19, 2023
c26dfd5
fix: fix admin page bugs
henilp105 May 19, 2023
28a6dff
fix: fix admin page bugs
henilp105 May 19, 2023
6abb823
fix: only allow the packages and namespaces and tarballs for the clone
henilp105 May 19, 2023
7e14cb2
disable account transfer API
henilp105 May 19, 2023
6a7ebfa
admin navbar setting
henilp105 May 20, 2023
9ff37cf
Merge branch 'fortran-lang:main' into main
henilp105 May 21, 2023
b06456e
Merge branch 'fortran-lang:main' into main
henilp105 May 25, 2023
2e68e53
Merge branch 'main' into main
henilp105 Jun 2, 2023
91e7f0c
fix: bugs
henilp105 Jun 3, 2023
1d017a3
fix: verify email reducer
henilp105 Jun 3, 2023
9dd0ebf
feat: add dry run
henilp105 Jun 3, 2023
24d4827
feat: add support for zip and tarballs
henilp105 Jun 3, 2023
c0289a7
fix : #38
henilp105 Jun 3, 2023
0467b4c
fix: handle invalid package metadata
henilp105 Jun 3, 2023
84e6eb3
fix: help styling
henilp105 Jun 3, 2023
be244f4
fix: handle extraction of toml from tar and zip, fix dry run
henilp105 Jun 3, 2023
8fa5859
resolve merge conflicts
henilp105 Jun 3, 2023
6570868
Merge branch 'fortran-lang:main' into main
henilp105 Jun 7, 2023
b08f99a
fix: emails
henilp105 Jun 7, 2023
e3cfb32
Merge branch 'main' of https://github.com/henilp105/registry
henilp105 Jun 7, 2023
0765971
fix: email verification
henilp105 Jun 7, 2023
0cd68d9
fix: changes and buttons animation and add verification
henilp105 Jun 7, 2023
5167625
fix: auth reducers
henilp105 Jun 7, 2023
3123920
fix: auth
henilp105 Jun 7, 2023
ab9a265
feat: Support multiple tarballs format
henilp105 Jun 12, 2023
0270d0e
fix: account
henilp105 Jun 12, 2023
e8a1d3f
add: reducers and actions for email change
henilp105 Jun 12, 2023
4bbff42
update dependencies
henilp105 Jun 12, 2023
5f37ef4
fix: tarballs
henilp105 Jun 12, 2023
6dd7257
Merge branch 'main' into main
henilp105 Jun 12, 2023
7958909
fix: alt rendering
henilp105 Jun 12, 2023
25082b1
Merge branch 'main' of https://github.com/henilp105/registry
henilp105 Jun 12, 2023
4d5f787
fix: toml extraction
henilp105 Jun 13, 2023
715f4fa
fix: auth bug and namespace rendering
henilp105 Jun 13, 2023
bd162f4
restrict non verified emails
henilp105 Jun 13, 2023
78a4b2b
restrict non verified emails
henilp105 Jun 13, 2023
0aee1a4
restrict non verified emails fix API response
henilp105 Jun 13, 2023
af4da33
fix: verify email loader
henilp105 Jun 13, 2023
09ad559
feat: add archives UI
henilp105 Jun 13, 2023
59f45ad
feat: add reducers for archives
henilp105 Jun 13, 2023
158d19c
fix: add actions
henilp105 Jun 13, 2023
0cf64f3
fix: add archives UI
henilp105 Jun 13, 2023
2de3636
feat: add docs for mongodump
henilp105 Jun 13, 2023
8c12889
fix: docker and fpm
henilp105 Jun 14, 2023
fef1cd4
fix: docker file
henilp105 Jun 14, 2023
77d7e45
fix: APIs for package upload and docker validate
henilp105 Jun 14, 2023
3528f1c
fix: change email restrict
henilp105 Jun 14, 2023
96379d1
fix: auth
henilp105 Jun 15, 2023
277ff35
fix: auth
henilp105 Jun 15, 2023
40f4b9f
auth
henilp105 Jun 15, 2023
cae240a
fix: mail
henilp105 Jun 15, 2023
1263396
fix: reset password bug
henilp105 Jun 16, 2023
523f885
Merge branch 'main' into main
henilp105 Jun 22, 2023
ca865f1
fix: reset password auth
henilp105 Jun 22, 2023
64b679e
notify user
henilp105 Jun 23, 2023
dddedc5
fix: add loading and notification
henilp105 Jun 25, 2023
de439df
fix: login page
henilp105 Jun 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
# registry
Registry for Fortran package manager

Currently for the testing phase :
1. backend APIs are hosted at: http://registry-apis.vercel.app/
2. frontend is hosted at: https://registry-frontend.vercel.app/
3. Documentation for the APIs are available at: https://registry-apis.vercel.app/apidocs/

*** Please note: the current registry is a playground: its database will be fully deleted once its functionality is established. Please do not use it for production yet! more information will follow then. ****

The fpm release [0.8.2](https://fortran-lang.discourse.group/t/fpm-version-0-8-2-released-centralized-registry-playground/5792) introduces fpm support for uploading packages to the fpm-registry server directly from the command-line interface, via
```
fpm publish --token <token-here>
```

fpm will now interact with a web interface that will help to manage the namespaces & packages.


## Python Flask app with Nginx and Mongo database

Project structure:
Expand Down
76 changes: 75 additions & 1 deletion flask/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def signup():

if not registry_user:
db.users.insert_one(user)

# send_verify_email(email) #TODO: uncomment this line
henilp105 marked this conversation as resolved.
Show resolved Hide resolved
return (
jsonify(
{
Expand Down Expand Up @@ -266,3 +266,77 @@ def forgot_password(*email):
jsonify({"message": "Password reset link sent to your email", "code": 200}),
200,
)


def send_verify_email(email):

user = db.users.find_one({"email": email})

if not user:
return jsonify({"message": "User not found", "code": 404}), 404

uuid = generate_uuid()
db.users.update_one({"email": email}, {"$set": {"uuid": uuid}})

message = f"""\n
Dear {user['username']},

We received a request to verify your email. To verify your email, please copy paste the link below in a new browser window:

{env_var['host']}/account/verify/{uuid}

Thank you,
The Fortran-lang Team"""

message = f'Subject: Verify email \nTo: {email}\n{message}'

# sending the mail
smtp.sendmail(to_addrs=email, msg=message, from_addr=fortran_email)

return (
jsonify({"message": "verification link sent to your email", "code": 200}),
200,
)

@app.route("/auth/verify-email", methods=["POST"])
def verify_email():
uuid = request.form.get("uuid")

if not uuid:
return jsonify({"message": "Unauthorized", "code": 401}), 401

user = db.users.find_one({"uuid": uuid})

if not user:
return jsonify({"message": "User not found", "code": 404}), 404

return jsonify({"message": "Successfully Verified Email", "code": 200}), 200

@app.route("/auth/change-email", methods=["POST"])
def change_email():
uuid = request.form.get("uuid")
new_email = request.form.get("new_email")

if not uuid:
return jsonify({"message": "Unauthorized", "code": 401}), 401

user = db.users.find_one({"uuid": uuid})

if not user:
return jsonify({"message": "User not found", "code": 404}), 404

if not new_email:
return jsonify({"message": "Please enter new email", "code": 400}), 400

used_email = db.users.find_one({"email": new_email})

if used_email:
return jsonify({"message": "Email already in use", "code": 400}), 400

db.users.update_one(
{"uuid": uuid},
{"$set": {"email": new_email}},
)
send_verify_email(new_email)

return jsonify({"message": "Email id Successfully changed", "code": 200}), 200
22 changes: 20 additions & 2 deletions flask/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from datetime import datetime, timedelta
from auth import generate_uuid
from app import swagger
import zipfile
import toml
from flasgger.utils import swag_from
from urllib.parse import unquote
import math
Expand Down Expand Up @@ -184,6 +186,10 @@ def upload():
file_object_id = file_storage.put(tarball, content_type="application/gzip", filename=tarball_name)



# Extract the package metadata from the tarball's fpm.toml file.
package_data = extract_fpm_toml(tarball_name)

# TODO: Uncomment this when the package validation is enabled

# validate the package
Expand All @@ -197,7 +203,9 @@ def upload():
package_obj = {
"name": package_name,
"namespace": namespace_doc["_id"],
"description": "Sample Test description",
"description": package_data["description"],
henilp105 marked this conversation as resolved.
Show resolved Hide resolved
"homepage": package_data["homepage"],
"repository": package_data["repository"],
"license": package_license,
"createdAt": datetime.utcnow(),
"updatedAt": datetime.utcnow(),
Expand Down Expand Up @@ -416,6 +424,8 @@ def get_package(namespace_name, package_name):
"name": package["name"],
"namespace": namespace["namespace"],
"description": package["description"],
"repository": package["repository"],
"homepage": package["homepage"],
"latest_version_data": {
"dependencies": package["versions"][-1]["dependencies"],
"version": package["versions"][-1]["version"],
Expand Down Expand Up @@ -606,4 +616,12 @@ def checkUserUnauthorized(user_id, package_namespace):
admins_id_list = [str(obj_id) for obj_id in package_namespace["admins"]]
maintainers_id_list = [str(obj_id) for obj_id in package_namespace["maintainers"]]
str_user_id = str(user_id)
return str_user_id not in admins_id_list and str_user_id not in maintainers_id_list
return str_user_id not in admins_id_list and str_user_id not in maintainers_id_list

def extract_fpm_toml(file_obj):
with zipfile.ZipFile(file_obj, 'r') as zip_ref:
zip_ref.extract("fpm.toml")
with open("fpm.toml", 'r') as file:
data = toml.load(file)

return data
1 change: 1 addition & 0 deletions flask/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ flasgger
license-expression
semantic-version
docker
toml
5 changes: 5 additions & 0 deletions registry/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import NoPage from "./pages/404";
import UserPage from "./pages/user";
import PackagePage from "./pages/package";
import NamespaceForm from "./pages/createNamespace";
import VerifyEmail from "./pages/verifyemail";
import NamespacePage from "./pages/namespace";
import AdminSection from "./pages/admin";
import ForgotPassword from "./pages/forgotpassword";
Expand All @@ -32,6 +33,10 @@ function App() {
path="/account/reset-password/:uuid"
element={<ResetPassword />}
/>
<Route
henilp105 marked this conversation as resolved.
Show resolved Hide resolved
path="/account/verify/:uuid"
element={<VerifyEmail />}
/>
<Route path="/account/register" element={<Register />} />
<Route path="/help" element={<Help />} />
<Route path="/search" element={<Search />} />
Expand Down
2 changes: 1 addition & 1 deletion registry/src/pages/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const AdminSection = () => {
// const [newPassword, setNewPassword] = useState("");

useEffect(() => {
dispatch(adminAuth());
dispatch(adminAuth(uuid));
if (!isAdmin) {
navigate("/404");
}
Expand Down
3 changes: 2 additions & 1 deletion registry/src/pages/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
import Spinner from "react-bootstrap/Spinner";
import Container from "react-bootstrap/Container";
import { Link } from "react-router-dom";
import AddMaintainerFormDialog from "./addMaintainerDialogForm";
import RemoveMaintainerFormDialog from "./removeMaintainerDialogForm";
import GenerateNamespaceTokenDialogForm from "./generateNamespaceTokenDialogForm";
Expand Down Expand Up @@ -155,7 +156,7 @@ const Dashboard = () => {
function Namespaces() {
return namespaces.length === 0 ? (
<div className="alert alert-secondary" role="alert">
You are not a maintainer of any namespace yet.
You are not a maintainer of any namespace yet. Add a namespace <Link to="/namespace/create">here</Link>
</div>
) : (
<Row>
Expand Down
15 changes: 14 additions & 1 deletion registry/src/pages/help.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import React from "react";

const Help = () => {
henilp105 marked this conversation as resolved.
Show resolved Hide resolved
return <p>help</p>;
return (<div>
<p>First of all, you will need to register a user account:</p>
<p>For uploading your package to the registry, you will have to step by step follow the following points:</p>
<p>Register yourself as a user. You will require a unique username, email & password to set up your account.</p>
<p>For uploading a package from fpm, you will have to first create a namespace. A namespace represents a collection of packages. Each package is published under a namespace in order to avoid collision of same package names. Namespace names will be unique always.
Now, that you will have created a namespace with a unique name and a nice description. You can go to dashboard by from the dropdown options in the Navigation bar on top.
In the dashboard, you can see the namespace that has been created by you. You can now generate a token for this namespace.</p>
<p>This token will be valid for 1 week , but you can always generate a new token.</p>
<p> Use this token to upload packages from the fpm using the CLI:</p>
<code>fpm publish --token token-here </code>
<p>After completing the above steps, you will receive a response in the fpm command line interface whether your upload was successful or not.

If your upload was successful, you can now again go to the registry frontend and check the dashboard. It should display the package uploaded by you.
You can now Add/Remove maintainers to your package. Mantainers have the rights to operate on the same package.</p></div>);
};

export default Help;
10 changes: 9 additions & 1 deletion registry/src/pages/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { login, resetErrorMessage } from "../store/actions/authActions";
import { Link } from "react-router-dom";
import Spinner from "react-bootstrap/Spinner";
import Container from "react-bootstrap/Container";

const Login = () => {
Expand All @@ -14,6 +15,7 @@ const Login = () => {

const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
const errorMessage = useSelector((state) => state.auth.error);
const isLoading = useSelector((state) => state.auth.isLoading);

useEffect(() => {
if (isAuthenticated) {
Expand Down Expand Up @@ -49,7 +51,7 @@ const Login = () => {
}
};

return (
return !isLoading ? (
<Container style={{ paddingTop: 25 }}>
<form id="login-form" onSubmit={handleSubmit}>
<h1>Welcome to fpm Registry!</h1>
Expand Down Expand Up @@ -84,6 +86,12 @@ const Login = () => {
</p>
</form>
</Container>
) : (
henilp105 marked this conversation as resolved.
Show resolved Hide resolved
<Container style={{ margin: "200px" }}>
<Spinner animation="border" role="status">
<span className="visually-hidden">Loading...</span>
</Spinner>
</Container>
);
};

Expand Down
5 changes: 2 additions & 3 deletions registry/src/pages/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,15 @@ export default PackagePage;
const sideBar = (data) => {
return (
<MDBCol size="3">
{/* TODO: update Package API for url,website,maintainers */}
<p style={{ fontSize: 16, textAlign: "left" }}>Install</p>
<code>
fpm install {data.namespace}/{data.name}
</code>
<p style={{ fontSize: 16, textAlign: "left" }}>Repository</p>
{/* <Container> { data.url }</Container> */}
<Container> { data.repository }</Container>
<hr></hr>
<p style={{ fontSize: 16, textAlign: "left" }}>Homepage</p>
{/* <Container>{ data.website }</Container> */}
<Container>{ data.homepage }</Container>
<hr></hr>
<p style={{ fontSize: 16, textAlign: "left" }}>License</p>
{data.license}
Expand Down
10 changes: 9 additions & 1 deletion registry/src/pages/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { signup, resetErrorMessage } from "../store/actions/authActions";
import { Link } from "react-router-dom";
import Spinner from "react-bootstrap/Spinner";
import Container from "react-bootstrap/Container";

const Register = () => {
Expand All @@ -14,6 +15,7 @@ const Register = () => {
const dispatch = useDispatch();

const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
const isLoading = useSelector((state) => state.auth.isLoading);
const errorMessage = useSelector((state) => state.auth.error);

const handleSubmit = async (e) => {
Expand Down Expand Up @@ -54,7 +56,7 @@ const Register = () => {
return Object.keys(errors).length === 0;
};

return (
return !isLoading ? (
<Container style={{ paddingTop: 25 }}>
<form id="login-form" onSubmit={handleSubmit}>
<h1>Welcome to fpm Registry!</h1>
Expand Down Expand Up @@ -98,8 +100,14 @@ const Register = () => {
<Link to="/account/forgot-password"> Forgot password </Link>
</p>
</form>
</Container> ) : (
henilp105 marked this conversation as resolved.
Show resolved Hide resolved
<Container style={{ margin: "200px" }}>
<Spinner animation="border" role="status">
<span className="visually-hidden">Loading...</span>
</Spinner>
</Container>
);

};

export default Register;
38 changes: 38 additions & 0 deletions registry/src/pages/verifyemail.js
henilp105 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { useState } from "react";
import { useParams } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { verify } from "../store/actions/verifyEmailActions";
import { Link } from "react-router-dom";
import Container from "react-bootstrap/Container";

const VerifyEmail = () => {
const { uuid } = useParams();
const dispatch = useDispatch();
const message = useSelector((state) => state.verifyemail.message);
const statuscode = useSelector((state) => state.verifyemail.statuscode);

const handleSubmit = async (e) => {
e.preventDefault();
dispatch(verify(uuid));
};

return (
<Container style={{ paddingTop: 25 }} onLoad={handleSubmit}>
<form id="login-form" onSubmit={handleSubmit}>
<h1>Welcome to fpm Registry!</h1>
<h3>Verify your email</h3>
{message &&
(statuscode !== 200 ? (
<p className="error">{message}</p>
) : (
<p className="success">{message}</p>
))}
<p>
Already have an account?<Link to="/account/login"> Login </Link>
</p>
</form>
</Container>
);
};

export default VerifyEmail;
Loading