Skip to content

Commit

Permalink
Merge pull request #46 from solun-pm/dev
Browse files Browse the repository at this point in the history
Added API Access Switch
  • Loading branch information
DanielWTE authored Nov 4, 2023
2 parents 318d324 + 8cb86a0 commit fd94a7d
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 5 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,15 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

- name: Restart Node 1
- name: Restart Node 1 Main
if: github.ref == 'refs/heads/main'
run: |
curl -X POST ${{ secrets.RESTART_URL }}
- name: Restart Node 1 Dev
if: github.ref == 'refs/heads/dev'
run: |
curl -X POST ${{ secrets.RESTART_URL_DEV }}
- name: Setup Node.js environment
uses: actions/[email protected]
Expand Down
123 changes: 123 additions & 0 deletions components/settings/apiAccess.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React, { useState, Fragment, useRef, useEffect } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faLock, faCircleNotch } from "@fortawesome/free-solid-svg-icons";
import toast from "react-hot-toast";
import { CopyToClipboard } from 'react-copy-to-clipboard';

function ApiAccess({ userDetails, userApiDetails }: any) {
const [token, setToken] = useState("");
const [apiAccess, setApiAccess] = useState(false);
const [apiAccessLoading, setApiAccessLoading] = useState(false);

useEffect(() => {
if (userDetails.api_access) {
setApiAccess(true);
if(userApiDetails === null) {
setToken("No token found.");
toast.error("No token found, please re-enable API access.");
return;
}
setToken(userApiDetails.token);
} else {
setApiAccess(false);
}
}, [userDetails, userApiDetails]);

const toggleApiAccess = async () => {
setApiAccessLoading(true);
const res = await fetch(process.env.NEXT_PUBLIC_API_DOMAIN + "/user/api_access", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user_id: userDetails.user_id,
api_access: !apiAccess,
}),
});

const data = await res.json();

if (!res.ok) {
toast.error(data.message);
setApiAccessLoading(false);
return;
}

setApiAccessLoading(false);
setApiAccess(!apiAccess);
setToken(data.token);
toast.success(data.message);
};

return (
<div className="bg-slate-900 p-5 rounded-lg shadow-md max-w-lg mt-4">
<h2 className="text-xl font-bold mb-2">API Settings</h2>

<div className="mt-6">
<h3 className="text-lg font-semibold mb-2">API Access</h3>
<p className="text-md mb-4 text-slate-300">
Enable this to get access to the Solun API, with this you can fetch mails,
create accounts and more.
</p>
<div className="flex justify-between gap-4">
{!apiAccess ? (
<button
type="button"
onClick={toggleApiAccess}
disabled={apiAccessLoading}
className="bg-blue-500 hover:bg-blue-600 text-white font-bold px-3 py-3 rounded transition duration-200"
>
{apiAccessLoading && (
<FontAwesomeIcon
icon={faCircleNotch}
className="animate-spin mr-2"
/>
)}
Enable
</button>
) : (
<button
type="button"
onClick={toggleApiAccess}
disabled={apiAccessLoading}
className="bg-red-500 hover:bg-red-600 text-white font-bold px-3 py-3 rounded transition duration-200"
>
{apiAccessLoading && (
<FontAwesomeIcon
icon={faCircleNotch}
className="animate-spin mr-2"
/>
)}
Disable
</button>
)}
</div>
</div>

{apiAccess && (
<div className="mt-6">
<h3 className="text-lg font-semibold mb-2">API Token</h3>
<p className="text-md mb-4 text-slate-300">
Copy your unique token, and follow our documentation to get started.
</p>
<div className="flex justify-between gap-4">
<div className="bg-slate-800 rounded-lg p-3">
<p className="text-md text-slate-300 blur-md hover:blur-none transition-all break-all">{token}</p>
</div>
<CopyToClipboard text={token}>
<button
type="button"
className="bg-blue-500 hover:bg-blue-600 text-white font-bold px-3 py-3 rounded transition duration-200">
Copy
</button>
</CopyToClipboard>
</div>
</div>
)}
</div>
);
}

export default ApiAccess;
41 changes: 41 additions & 0 deletions hooks/fetchUserApiToken.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";

export const useFetchUserApiToken = () => {
const [userApiDetails, setUserApiDetails] = useState(null);
const router = useRouter();

useEffect(() => {
const fetchUserInfo = async () => {
const token = localStorage.getItem("jwt");

if (!token) {
router.push("/login");
return;
}

const response = await fetch(process.env.NEXT_PUBLIC_API_DOMAIN + "/user/get_api_details", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
token: token,
}),
});

if (!response.ok) {
localStorage.removeItem("jwt");
router.push("/login");
return;
}

const data = await response.json();
setUserApiDetails(data.data);
};

fetchUserInfo();
}, []);

return { userApiDetails };
};
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "solun-auth",
"version": "0.3.53",
"version": "0.3.60",
"private": true,
"scripts": {
"dev": "next dev",
Expand Down
4 changes: 4 additions & 0 deletions pages/subpages/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ import ChangePassword from "@/components/settings/changePassword";
import PrivacySettings from "@/components/settings/privacySettings";
import { useFetchUserInfo } from "@/hooks/fetchUserInfo";
import Recovery from "@/components/settings/recovery";
import { useFetchUserApiToken } from "@/hooks/fetchUserApiToken";
import ApiAccess from "@/components/settings/apiAccess";

const SettingsPage = () => {
const router = useRouter();
const { userInfo, userDetails } = useFetchUserInfo() as any;
const { userApiDetails } = useFetchUserApiToken() as any;

if (!userInfo || !userDetails) {
return null;
Expand All @@ -25,6 +28,7 @@ const SettingsPage = () => {
<ChangePassword userInfo={userInfo} />
<TwoFactorAuthSetup userDetails={userDetails} userInfo={userInfo} />
<Recovery userDetails={userDetails} userInfo={userInfo} />
<ApiAccess userDetails={userDetails} userApiDetails={userApiDetails} />
</div>
<div className="flex flex-col">
<PrivacySettings userDetails={userDetails} userInfo={userInfo} />
Expand Down

0 comments on commit fd94a7d

Please sign in to comment.