teach-yourself-code
所属分类:后台框架
开发工具:JavaScript
文件大小:0KB
下载次数:0
上传日期:2023-02-03 05:14:10
上 传 者:
sh-1993
说明: 学习编程平台。使用Next.js(React)、Apollo GraphQL和Bulma构建。
(Learn to program platform. Being built with Next.js (React), Apollo-GraphQL, and Bulma.)
文件列表:
.babelrc (32, 2022-06-07)
.vscode/ (0, 2022-06-07)
.vscode/settings.json (31, 2022-06-07)
LICENSE (1080, 2022-06-07)
components/ (0, 2022-06-07)
components/BackButton.jsx (364, 2022-06-07)
components/Card.jsx (143, 2022-06-07)
components/Layout/ (0, 2022-06-07)
components/Layout/index.jsx (1650, 2022-06-07)
components/Loader.jsx (91, 2022-06-07)
components/Menus/ (0, 2022-06-07)
components/Menus/BottomBar.jsx (1765, 2022-06-07)
components/Menus/Sidebar.jsx (4649, 2022-06-07)
components/Notes/ (0, 2022-06-07)
components/Notes/NotesList.jsx (1537, 2022-06-07)
components/SignUpCTA.jsx (352, 2022-06-07)
components/Tutorial/ (0, 2022-06-07)
components/Tutorial/Description.jsx (314, 2022-06-07)
components/Tutorial/TutorialCard.jsx (835, 2022-06-07)
components/User/ (0, 2022-06-07)
components/User/CreateAccount.jsx (107, 2022-06-07)
components/User/ForgotPassword.jsx (109, 2022-06-07)
components/User/Profile.jsx (134, 2022-06-07)
components/User/SignIn.jsx (94, 2022-06-07)
components/Video/ (0, 2022-06-07)
components/Video/Video.jsx (3514, 2022-06-07)
components/Video/VideoCard.jsx (920, 2022-06-07)
components/Video/VideoList.jsx (443, 2022-06-07)
components/View/ (0, 2022-06-07)
components/View/index.jsx (101, 2022-06-07)
cypress.json (3, 2022-06-07)
cypress/ (0, 2022-06-07)
cypress/fixtures/ (0, 2022-06-07)
cypress/fixtures/example.json (154, 2022-06-07)
cypress/integration/ (0, 2022-06-07)
cypress/integration/examples/ (0, 2022-06-07)
cypress/integration/examples/actions.spec.js (10438, 2022-06-07)
cypress/integration/examples/aliasing.spec.js (1104, 2022-06-07)
... ...
# Teach Yourself Code
- A free platform for learning programming that curates tutorials from Youtube; the main value propositions are that...
1. Users will be able to watch videos with minimal distraction/in a 'focus' mode
2. Users will be able to 'subscribe' to tutorials/save them to their profile
3. Users will be able to add notes to each video
## Tech Stack
- [NextJs](https://nextjs.org/) - a React framework
- [Redux-Toolkit](https://redux-toolkit.js.org/) - state container
- [Hasura](https://hasura.io/) - a GraphQL engine for querying a Postgres database
- [Auth0](https://auth0.com/) - authentication provider
- [Apollo GraphQL](https://www.apollographql.com/docs/react/) - GraphQL hooks for fetching data from database
- [Bulma](https://bulma.io/) - open-source CSS framework
- [Jest](https://jestjs.io/en/) - unit-testing library
- [Vercel](https://vercel.com/) - serverless hosting
## To Get It Up And Running Locally
### Install locally
```
yarn install
yarn run dev
```
### Obtain the following .env variables by setting up YouTube API, Hasura, and Auth0:
Create a .env file in your project root with:
```
AUTH0_DOMAIN =
AUTH0_CLIENT_ID =
AUTH0_CLIENT_SECRET =
REDIRECT_URI= http://localhost:3000/api/callback
POST_LOGOUT_REDIRECT_URI= http://localhost:3000/
SESSION_COOKIE_SECRET =
SESSION_COOKIE_LIFETIME = 7200, // 2 hours
YOUTUBE_API_KEY =
```
**Get the vars by following these:**
1. Sign-up for a YouTube API key. [Follow This](https://www.slickremix.com/docs/get-api-key-for-youtube/)
```
YOUTUBE_API_KEY=
```
2. Set-up a [Hasura GraphQL Engine](https://github.com/hasura/graphql-engine) to obtain the following values. Hasura is used to query our Postgres db. The quickest option for setup is via a [free Heroku server](https://hasura.io/docs/1.0/graphql/manual/deployment/heroku/index.html)
=======
```
HASURA_ADMIN_SECRET=
HASURA_GRAPHQL_JWT_SECRET=
HASURA_ENDPOINT=
```
Hasura admin secret Docs are [here](https://hasura.io/docs/1.0/graphql/manual/deployment/heroku/securing-graphql-endpoint.html#add-the-hasura-graphql-admin-secret-env-var).
Hasura graphql jwt secret can be generated [here](https://hasura.io/jwt-config/).
Add jwt Secret to the env vars as you did for `HASURA_ADMIN_SECRET`.
3. Create a free account at Auth0 and set-up a test application following the [Auth0 config instructions here](https://auth0.com/docs/quickstart/spa/react#configure-auth0). It explains where to get the following values:
```
AUTH0_DOMAIN=
AUTH0_CLIENT_ID=
AUTH0_CLIENT_SECRET=
```
4. Create a 32-character secret with a random string generator like [this](https://passwordsgenerator.net/).
```
SESSION_COOKIE_SECRET=jtftEOwNtDLVwRw0OgrdzsZDeQIeP9yioxPKlgrS5bIVXoPSMP_u-VT4saodFOqN
```
5. Add localhost URLs for redirection upon login and logout.
```
REDIRECT_URI=http://localhost:3000/api/callback
POST_LOGOUT_REDIRECT_URI=http://localhost:3000/
```
### Create the following rules in your Auth0 Dashboard
Directly through Dashbaord, Under the tab `Rules`.
Do remember to change the `url: ""` in `hasura-user-sync` function.
1. hasura-jwt-claim
```
function hasuraClaimsRule(user, context, callback) {
const namespace = "https://hasura.io/jwt/claims";
context.idToken[namespace] = {
"x-hasura-default-role": "user",
// do some custom logic to decide allowed roles
"x-hasura-allowed-roles": ["user"],
"x-hasura-user-id": user.user_id
};
callback(null, user, context);
}
```
2. hasura-user-sync
```
function userSyncRule(user, context, callback) {
const userId = user.user_id;
const email = user.email;
const mutation = `mutation($userId: String!, $email: String) {
insert_users(objects: [{
auth0_id: $userId,
email: $email
}],
on_conflict: {
constraint: users_pkey,
update_columns: [last_seen, email]
}) {
affected_rows
}
}`;
request.post(
{
headers: {
"content-type": "application/json",
"x-hasura-admin-secret": configuration.ACCESS_KEY
},
url: "",
body: JSON.stringify({ query: mutation, variables: { userId, email } })
},
function(error, response, body) {
console.log(body);
callback(error, user, context);
}
);
}
```
### Set up Postgres Database via Hasura Console
Run the following SQL command.
```
CREATE FUNCTION public.set_current_timestamp_updated_at() RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$;
CREATE TABLE public.users (
id integer NOT NULL,
auth0_id text NOT NULL,
email text NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
last_seen timestamp with time zone DEFAULT now() NOT NULL,
current_playlist_id integer
);
CREATE TABLE public.notes (
id integer NOT NULL,
note text NOT NULL,
video_id text NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
user_id text NOT NULL,
"timestamp" integer
);
CREATE SEQUENCE public.notes_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.notes_id_seq OWNED BY public.notes.id;
CREATE VIEW public.online_users AS
SELECT users.email,
users.last_seen
FROM public.users
WHERE (users.last_seen >= (now() - '00:00:30'::interval));
CREATE TABLE public.playlists (
id integer NOT NULL,
title text NOT NULL,
description text,
thumbnail text,
topic_id integer NOT NULL,
playlist_id text NOT NULL,
channel text
);
CREATE SEQUENCE public.playlists_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.playlists_id_seq OWNED BY public.playlists.id;
CREATE TABLE public.topics (
id integer NOT NULL,
title text NOT NULL
);
CREATE SEQUENCE public.topics_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.topics_id_seq OWNED BY public.topics.id;
CREATE TABLE public.user_playlists (
id integer NOT NULL,
user_id integer NOT NULL,
playlist_id integer NOT NULL,
current_video_id text
);
CREATE SEQUENCE public.user_playlists_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.user_playlists_id_seq OWNED BY public.user_playlists.id;
CREATE SEQUENCE public.users_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id;
ALTER TABLE ONLY public.notes ALTER COLUMN id SET DEFAULT nextval('public.notes_id_seq'::regclass);
ALTER TABLE ONLY public.playlists ALTER COLUMN id SET DEFAULT nextval('public.playlists_id_seq'::regclass);
ALTER TABLE ONLY public.topics ALTER COLUMN id SET DEFAULT nextval('public.topics_id_seq'::regclass);
ALTER TABLE ONLY public.user_playlists ALTER COLUMN id SET DEFAULT nextval('public.user_playlists_id_seq'::regclass);
ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass);
ALTER TABLE ONLY public.notes
ADD CONSTRAINT notes_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.playlists
ADD CONSTRAINT playlists_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.topics
ADD CONSTRAINT topics_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.user_playlists
ADD CONSTRAINT user_playlists_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.users
ADD CONSTRAINT users_auth0_id_key UNIQUE (auth0_id);
ALTER TABLE ONLY public.users
ADD CONSTRAINT users_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.notes
ADD CONSTRAINT notes_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(auth0_id) ON UPDATE RESTRICT ON DELETE RESTRICT;
ALTER TABLE ONLY public.playlists
ADD CONSTRAINT playlists_topic_id_fkey FOREIGN KEY (topic_id) REFERENCES public.topics(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
ALTER TABLE ONLY public.user_playlists
ADD CONSTRAINT user_playlists_playlist_id_fkey FOREIGN KEY (playlist_id) REFERENCES public.playlists(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
ALTER TABLE ONLY public.user_playlists
ADD CONSTRAINT user_playlists_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
ALTER TABLE ONLY public.users
ADD CONSTRAINT users_current_playlist_id_fkey FOREIGN KEY (current_playlist_id) REFERENCES public.playlists(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
```
### Build for Production
```
yarn run build
```
近期下载者:
相关文件:
收藏者: