Giter Site home page Giter Site logo

swsnu / swpp2021-team9 Goto Github PK

View Code? Open in Web Editor NEW
3.0 4.0 3.0 5.06 MB

๐ŸŽธMetaBand, where anyone can create covers and combine them into a band!

JavaScript 2.95% Shell 0.14% Handlebars 0.74% TypeScript 64.74% HTML 0.28% Python 18.08% CSS 0.34% Dockerfile 0.27% Jupyter Notebook 12.46%
music band recording

swpp2021-team9's Introduction

MetaBand Build Status Quality Gate Status Coverage Status

In MetaBand, people can create band cover contents regardless of time and space. A cover is a performance of an existing song by other vocalists/instrumentalists. In MetaBand, you can record & upload song covers and listen to other people's covers.

MetaBand specializes in connectivity between covers. Among the covers of a particular song,

  1. Anyone can listen to combinations of any covers simultaneously, and
  2. Anyone can record/upload their own cover while listening to that combination.

For example, guitarist G may add guitar lines while listening to vocalist V's vocals and drummer D's drums. Another vocalist V2 may hear G's guitars and record their own vocals to it. These kinds of interactions make it possible to have limitless amount of cover combinations. A combination of covers is called a MetaBand (metaverse + band), since it is essentially a band formed virtually.

MetaBand aims to be a place for people of any musical background, where one can musically connect with others without any constraints of offline meetings.



Instructions

Installation

source ~/virtualenv/python3.7/bin/activate
pip install -r backend/requirements.txt
cd frontend
yarn install
cd ..

Frontend Running

cd frontend
yarn start

Backend Running

cd backend/app
python manage.py migrate
python manage.py runserver

Frontend Testing

cd frontend
yarn test --coverage --watchAll=false

Backend Testing

cd backend/app
coverage run --source='.' manage.py test
coverage xml

swpp2021-team9's People

Contributors

ccdc-git avatar gogiants1 avatar uzrjny avatar zz-zye avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

davekjh gogiants1

swpp2021-team9's Issues

[Backend] Song Views

Feature description

Song Views song/main/, song/search/, song/info/<int:pk>/, song/ Without implementing machine learning

Screenshots / Additional context

[Frontend] Base URL

Feature description

  • tsconfig์— path ์ถ”๊ฐ€ํ•˜๊ธฐ. ์ด๊ฑธ ํ•˜๋ฉด '@/folder๋ช…'์œผ๋กœ import ๊ฐ€๋Šฅ(์ ˆ๋Œ€๊ฒฝ๋กœ?)

Screenshots / Additional context

image

[Frontend] Create Cover Page

Feature description

  • ์ปค๋ฒ„ ๊ณก ์ƒ์„ฑ ํŽ˜์ด์ง€
  • step 1
    • ์œ ํŠœ๋ธŒ ํ”Œ๋ ˆ์ด์–ด (react-player) ์„ ํƒ
    • ์„œ๋ฒ„์— ์ €์žฅ๋œ ๋งํฌ or ์Œ์› ์žฌ์ƒํ•˜๋Š” ํ”Œ๋ ˆ์ด์–ด ์ œ์ž‘
    • ๋…น์Œ ๋ฒ„ํŠผ ๋ฐ ๊ธฐ๋Šฅ
    • ์—…๋กœ๋“œ ๋ฒ„ํŠผ ๋ฐ ๊ธฐ๋Šฅ
  • step 2
    • ์ž์‹ ์ด ์—…๋กœ๋“œํ•œ ๊ฒƒ ๋‹ค์‹œ ๋“ฃ๊ธฐ (step 1์˜ ๋ฏธ๋‹ˆํ”Œ๋ ˆ์ด์–ด์™€ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ)
    • ๋’ค๋กœ๊ฐ€๊ธฐ
  • step 3
    • TBD

Screenshots / Additional context

react-player๋Š” ์‚ฌ์šด๋“œ ํด๋ผ์šฐ๋“œ, ์œ ํŠœ๋ธŒ, ํŠธ์œ„์น˜ ๋“ฑ ๋‹ค์–‘ํ•œ ํ”Œ๋žซํผ๊ณผ ์—ฐ๋™๋˜์–ด์žˆ์–ด์„œ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.
๋ฐ๋ชจ ์˜ˆ์‹œ
์ฝ”๋“œ

[Frontend] Get Youtube Thumbnail link

Feature description

์œ ํŠœ๋ธŒ ๋งํฌ๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ ์ธ๋„ค์ผ ๋งํฌ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ , ํ˜„์žฌ ์žˆ๋Š” ํŽ˜์ด์ง€๋“ค์— ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Screenshots / Additional context

Add README instructions

Feature description

Should add install/testing instructions in README.md

Screenshots / Additional context

[Backend] profile backend api

Feature description

Profile ํŽ˜์ด์ง€์—์„œ ์“ธ api ๋“ค backend ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค.

ํŒŒ์ผ์„ ์ „์†กํ•˜๊ธฐ ์œ„ํ•ด PUT์— multipart/form-data ํ˜•์‹์„ ์ง€์›ํ•˜์ง€ ์•Š์•„์„œ POST๋กœ ๋ฐ”๊พธ์—ˆ์Šต๋‹ˆ๋‹ค.
๊ด€๋ จ WIKI๋„ ์ˆ˜์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Screenshots / Additional context

[Server] Deploy

Feature description

ํ˜„์žฌ๊นŒ์ง€ ์ž‘์—…์„ ์„œ๋ฒ„์— ์˜ฌ๋ฆฌ๊ณ  sqlite๋ฅผ mySQL๋กœ ๋ฐ”๊พธ๋Š” ์ž‘์—… ์ง„ํ–‰

EC2 ์„œ๋ฒ„๊ฐ€ ๋งค์šฐ ๋Š๋ ค์„œ ์„œ๋ฒ„ ๋‚ด์—์„œ react buildํ•˜์ง€ ๋ชปํ•˜๊ณ  ๋กœ์ปฌ์—์„œ build ํ›„ docker hub๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๋กœ ์˜ฌ๋ผ๊ฐ€๋„๋ก ์ˆ˜์ • ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ SSL ์ž‘์—…์„ ๋๋‚ด๊ณ  CORS๋„ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
์„œ๋ฒ„ ๋‚ด๋ถ€ ์„ค์ •์— ๊ด€ํ•œ๊ฑฐ๋Š” secrets.jsonํŒŒ์ผ์— ๋„ฃ์–ด๋‘์–ด์„œ mysql์„ ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://metaband.space ๋กœ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Screenshots / Additional context

[Frontend] Wrapper Style

Feature description

Change Wrapper CSS style to tailwindCSS to unify styling method

Screenshots / Additional context

merge to mid

Feature description

mid ๋ฐœํ‘œ๋ฅผ ์œ„ํ•œ branch์™€ main๋ธŒ๋žœ์น˜๊ฐ„์˜ ์ถฉ๋Œ์ด ์žˆ์–ด์„œ mid์— main์„ mergeํ–ˆ์Šต๋‹ˆ๋‹ค.

Screenshots / Additional context

all/mergemain์ด mid๋กœ merge๋˜๋ฉด ๊ฐ์ž ์ž‘์—…ํ•˜๋˜ ๋ถ€๋ถ„์— ๋‹ค์‹œ mid๋ฅผ mergeํ•ด์„œ ์ž‘์—…ํ•˜๋ฉด ์ถฉ๋Œ์—†์ด main์— ์ ์šฉํ• ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Travis CI setting

Feature description

Setup Travis CI and SonarCloud by configuring .travis.yaml file

Screenshots / Additional context

Homework of SWPP practice session #9

[Frontend signin/signup/profile page]

Feature description

[signin /signup page]

  • signin / signup frontend ๋Š” testing ๊นŒ์ง€ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค!
  • backend ๋ถ€๋ถ„์€ ํƒœ์›๋‹˜์ด ์ˆ˜์ •ํ•ด์ฃผ์‹  ๋ถ€๋ถ„๊ณผ merge๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

[profile page]

  • following ์„ ์›๋ž˜ profile page ์— ํ‘œ์‹œํ•˜๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ, User format ์— ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์•„์„œ ์šฐ์„  ์ œ์™ธํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Testing ์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์•„ ์ถ”ํ›„ ํ…Œ์ŠคํŒ… ์ฝ”๋“œ๋Š” ๋” ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค !

Screenshots / Additional context

[Frontend] Create Wrapper

Feature description

Wapper ๋งŒ๋“ค๊ธฐ
Header

  • view ๊ทธ๋ฆฌ๊ธฐ
  • button onclick ์—ฐ๊ฒฐ

PlayerBar

  • progress ํ‘œ์‹œ
  • ๋ฒ„ํŠผ ์—ฐ๊ฒฐ
  • view ๊ทธ๋ฆฌ๊ธฐ

Player

  • ์—ฌ๋Ÿฌ audio๋ฅผ ํ•œ๋ฒˆ์— ์žฌ์ƒ
  • ๋‹ค์Œ, ์ด์ „, ๋ฉˆ์ถค ์ปจํŠธ๋กค
  • track ์ถ”๊ฐ€

Screenshots / Additional context

icon๊ฐ™์€ resource๋Š” res์— ์ €์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.
types.d.ts์— global๋กœ ์“ฐ์ผ ๋งŒํ•œ type๋“ค ๋ชจ์•„๋†จ์Šต๋‹ˆ๋‹ค.

app/helper์— ๋„์›€์ด ๋ ๋งŒํ•œ ์ฝ”๋“œ๋“ค ๋ชจ์•˜์Šต๋‹ˆ๋‹ค.

TrackPlayer

private audios: HTMLAudioElement[]
private track?: TrackInfo
private status: 'init' | 'loading' | 'loadFinish' | 'pause' | 'playing'
onStatusChange?: (status: string) => void;

  • setTrack(track)
    ์žฌ์ƒํ•  track ์„ ์„ค์ •
  • isPaused()
    ๋ฉˆ์ถค (every audio is paused)
  • play()
    ๋™์‹œ ์žฌ์ƒ
  • pause()
    ๋™์‹œ ๋ฉˆ์ถค
  • getDuration()
    ์ „์ฒด ํ”Œ๋ ˆ์ด ์‹œ๊ฐ„ (max of audio.duration)
  • getCurrentTime()
    ํ˜„์žฌ ์žฌ์ƒ ์‹œ๊ฐ„ (max of audio.๏ฟฝcurrentTime)
  • getMinReadyState()
    ํ˜„์žฌ ์˜ค๋””์˜ค ์ƒํƒœ (min of audio.readyState)

Player

๊ธฐ๋ณธ์ ์œผ๋กœ TrackPlayer์˜ Singletone๊ณผ tracks ๊ด€๋ฆฌ๋ฅผ ๋”ํ•œ ๊ฒƒ.

  • static getInstance()
    ์–ด๋””์„œ๋“ ์ง€ ๊ฐ™์€ player ๊ฐ€์ ธ์˜ค๊ธฐ
  • setIndex()
    track index๋กœ ์žฌ์ƒ
  • setTracks(tracks: TrackInfo[])
    ์ƒˆ๋กœ์šด tracks๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์ฒซ๋ฒˆ์งธ ์žฌ์ƒ
  • addTrack(TrackInfo)
    ์ƒˆ๋กœ์šด track์„ ํ˜„์žฌ ์žฌ์ƒ ์ด์ „์— ์ถ”๊ฐ€ํ•˜๊ณ  ๋ฐ”๋กœ ์žฌ์ƒ
  • playNext()
    ๋‹ค์Œ ๊ณก ์žฌ์ƒ
  • playPrev()
    ์ด์ „ ๊ณก ์žฌ์ƒ

image

[Frontend] Cover edit page

Feature description

์›๋ž˜๋Š” Coverpage์—์„œ ์ˆ˜์ •ํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ input์„ ๋ฐ›๋Š” ๊ฒƒ๊ณผ ๋ณด์—ฌ์ง€๋Š” ๊ฒƒ์„ ๋ถ„๋ฆฌํ•˜๋Š”๊ฒŒ ๋” ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์„œ ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

  • CoverEditPage ๋งŒ๋“ค๊ธฐ
  • Backend API์˜ /cover/info/ PUT ์—ฐ๊ฒฐ
  • ์ž‘๋™ ํ™•์ธ

Screenshots / Additional context

[Frontend] Like ์—ฐ๋™

Feature description

Like ๋ฒ„ํŠผ์ด ์ž‘๋™ํ•˜๋„๋ก ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ๋ฅผ ์—ฐ๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

Screenshots / Additional context

[Frontend] Cover Page

Feature description

Cover page ์ œ์ž‘

  • ๊ธฐ๋ณธ ์ •๋ณด ์ถœ๋ ฅ
  • ์Œ์•… ์žฌ์ƒ
  • ํ…Œ์ŠคํŠธ

Screenshots / Additional context

SonarCloud Code Smells

Description

Should refactor and remove SonarCloud Code Smells

Screenshots / Additional context

image

How to solve

Each person should refactor the code smells assigned to them as shown in the SonarCloud code smell screen.
Each person should open a branch to solve their code smells and make PRs.

image

By December 2nd, all 89 Code Smells (or all of the code smells left in that time) should be solved.

[Frontend] Recording Quality

Feature description

  • ๋…น์Œํ•  ๋•Œ, ์žก์Œ ์ œ๊ฑฐ๊ฐ€ ์‹ฌํ•˜๊ฒŒ ๋˜์–ด์„œ, ์•…๊ธฐ ์†Œ๋ฆฌ๊ฐ€ ๋…น์Œ์ด ์ž˜ ์•ˆ๋˜๋Š” ์ƒํ™ฉ ๋ฐœ์ƒ.

Screenshots / Additional context

[Frontend] Connect API

Feature description

axios๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐฑ์—”๋“œ์™€ ์—ฐ๊ฒฐํ•˜๋Š” ํ•จ์ˆ˜๋“ค์„ ๋งŒ๋“ค๊ธฐ

ํŒŒ์ผ ๊ตฌ์กฐ

src
  api
    band
      actions.ts
      actionTypes.ts
  actions.ts
  actionTypes.ts
  dummy.ts
  ...
...

๏ฟฝRedux-saga

official page
๋ฆฌ๋•์Šค ์‚ฌ๊ฐ€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋น„๋™๊ธฐ ํ˜ธ์ถœ์˜ ์ƒํƒœ (loading, error, success ๋“ฑ)์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ๋ฒˆ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์–ด์„œ apiํ˜ธ์ถœํ• ๋•Œ ์ƒํƒœ๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ์šฉ๋„๋กœ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
TypeAction์€ type ๋“ค์„ ์ง€์ •ํ•ด ์ฃผ๋Š”๋ฐ ๋„์›€์„ ์ฃผ๋Š” module์ž…๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋ฒ•

ํ˜„์žฌ CoverPage์— ์ ์šฉ์‹œ์ผœ ๋†“์€ ์ƒํƒœ์ด๊ณ , test์™€ slice๋ฅผ ๋งŒ๋“ค๋•Œ ์ด ๋ถ€๋ถ„์„ ์ฐธ๊ณ ํ•˜๋ฉด ๋ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. Action ๋“ฑ๋ก
    src/api/band/actionTypes.ts ํŒŒ์ผ ์•ˆ์— ์ƒˆ๋กœ์šด asyncAction์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
# src/api/band/actionTypes.ts

export const LOAD_COVER = asyncActionCreator('LOAD_COVER');

src/api/band/actions.ts ํŒŒ์ผ์— ์ƒˆ๋กœ์šด ์•ก์…˜์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
asyncAction์˜ generic type์€ ์ฒซ๋ฒˆ์งธ๋ถ€ํ„ฐ [request's input type], [data type], [error type]์ž…๋‹ˆ๋‹ค.

# src/api/band/action.ts

export const loadCover = asyncAction<number, Cover, string>(AT.LOAD_COVER);
  1. slice action ๋“ฑ๋ก
    src/containers/<Page>/slice/index.ts ์—์„œ type๊ณผ createSlice์— reducer๋ฅผ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.
# src/containers/CoverPage/slice/index.ts
...
/* --- STATE --- */
export interface CoverState {
  name: string;
  coverResponse: AsyncStateType<Cover>;
} // state ํ˜•์‹ ์ •์˜

export const initialState: CoverState = {
  name: 'cover',
  coverResponse: { loading: false },
};

const slice = createSlice({
  name: 'cover', // ์ด ์ด๋ฆ„์„ types/RootState.ts์— ์จ๋†“์•„์•ผ ํ•จ
  initialState,
  reducers: {
    loadingCoverResponse(state, action: PayloadAction<any>) {
      state.coverResponse = { loading: true };
      return state;
    },
    successCoverResponse(state, action: PayloadAction<Cover>) {
      state.coverResponse.loading = false;
      state.coverResponse.data = action.payload;
      return state;
    },
    errorCoverResponse(state, action: PayloadAction<string>) {
      state.coverResponse.loading = false;
      state.coverResponse.error = action.payload;
      return state;
    },
  },
});
...
// useCoverSlice ์— useInjectSaga์„ ์ถ”๊ฐ€ํ•ด ์ค๋‹ˆ๋‹ค.
export const useCoverSlice = () => {
  ...
  useInjectSaga({
    key: slice.name,
    saga: coverPageSaga,
  });
  ...
};

  1. saga.ts ๋งŒ๋“ค๊ธฐ
    container์˜ slice ํด๋” ์•ˆ์— saga.tsํŒŒ์ผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    ์‹ค์ œ ์ฝ”๋“œ์— ์ฃผ์„์„ ๋” ํ–ˆ์Šต๋‹ˆ๋‹ค.
# src/containers/CoverPage/slice/sags.ts
import { put, takeEvery } from 'redux-saga/effects';
import { coverActions } from '.';
import * as AT from 'api/actionTypes';
import * as actions from 'api/actions';
import { api } from 'api/band';
import { ActionType } from 'typesafe-actions';

// sagaํ•จ์ˆ˜๋“ค์„ ๋ชจ์•„์„œ slice/index.ts์—์„œ ๋“ฑ๋กํ•  saga์ž…๋‹ˆ๋‹ค. 
export default function* coverPageSaga(payload: any) {
  // action type์˜ REQUEST๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœํ•˜๋ฉด ๋’ค์— ๏ฟฝsaga ํ•จ์ˆ˜์ธ getCoverResponse ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  yield takeEvery(AT.LOAD_COVER.REQUEST, getCoverResponse);
}

// API๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.
export function* getCoverResponse(
  action: ActionType<typeof actions.loadCover.request>,
) {
  // ์ฒ˜์Œ ์‹œ์ž‘ํ•˜๋ฉด loading์„ ํ‘œ์‹œํ•ด ์ค๋‹ˆ๋‹ค.
  yield put(coverActions.loadingCoverResponse('start load'));
  try {
    const coverResponse = yield api.getCoverInfo(action.payload);
    // ์„ฑ๊ณตํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ๋“ฑ๋กํ•ด ์ค๋‹ˆ๋‹ค.
    yield put(coverActions.successCoverResponse(coverResponse));
  } catch (e: any) {
    // ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์—๋Ÿฌ๋ฅผ ์ „๋‹ฌํ•ด์ค๋‹ˆ๋‹ค.
    yield put(coverActions.errorCoverResponse(e));
  }
}

  1. Container์—์„œ ํ˜ธ์ถœ
    dispatch ๋ฅผ ์ด์šฉํ•ด์„œ ํ˜ธ์ถœํ•˜๋Š”๊ฑด ์ด์ „๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
const dispatch = useDispatch();

dispatch(apiActions.loadCover.request(Number(props.match.params.id)));

Api client and testing

axios client๋ฅผ ์ˆจ๊ฒจ์„œ test์— ์šฉ์ดํ•˜๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.
src/api/band/index.ts์•ˆ์— ๋ชจ๋“  api์— ๋Œ€ํ•œ ํ•จ์ˆ˜๋ฅผ ์ •๋ฆฌํ•ด ๋†“์•˜์Šต๋‹ˆ๋‹ค.
get ์š”์ฒญ์˜ ๊ฒฝ์šฐ์—๋Š” Http Response์—์„œ data๋ฅผ ๋ฐ›์•„์˜ค์ง€๋งŒ ๋‚˜๋จธ์ง€ ์š”์ฒญ์€ Http Request๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

// get
  getCoversBySongId: async (songId: number) => {
    const response = await apiClient.get<Cover[]>(`/api/cover/${songId}/`);
    return response.data;
  },

// others
  putCoverInfo: async (coverForm: CoverFormPut) => {
    return await apiClient.put<Cover>(
      `/api/cover/info/${coverForm.id}/`,
      coverForm,
    );
  },

ํ…Œ์ŠคํŠธ ํ• ๋•Œ api์— ๋Œ€ํ•ด์„œ ๊ฐ๊ฐ์˜ fn๋งŒ jest.fn์„ ํ†ตํ•ด mock ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค๋ฉด ์ธํ„ฐ๋„ท ๋ฌธ์ œ ์—†์ด ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  api.getCoverInfo = jest.fn(
    (coverId: number) =>
      new Promise((res, rej) => {
        res(dummyCovers[coverId]);
      }),
  );

Dummy

ํฉ์–ด์ ธ ์žˆ๋˜ dummy๋“ค์„ ํ•œ๊ตฐ๋ฐ๋กœ ๋ชจ์•˜์Šต๋‹ˆ๋‹ค.
src/api/dummy.ts

Screenshots / Additional context

[Backend] Combination views

Feature description

Neet do implement combination/songid/, combination/info/id/ views

Screenshots / Additional context

[Frontend] Main Page Album style

Feature description

Main Page์—์„œ ๊ฐ album์ด ํ†ต์ผ์„ฑ ์žˆ๊ฒŒ ํ‘œ์‹œ๋˜๋„๋ก style ์ˆ˜์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Screenshots / Additional context

image

album์˜ ์œ„์•„๋ž˜ ์ •๋ ฌ์ด ๋งž๋„๋ก ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

[backend] Hide secret key

Feature description

As Is : Current Secret key explicity written in settings.py file
To Be : Separate Secret key in a new file and hide the secret key

Screenshots / Additional context

Logo ๋ณ€๊ฒฝ

Feature description

Logo๋ฅผ bandcruit์—์„œ MetaBand๋กœ ๋ณ€๊ฒฝ

Screenshots / Additional context

[Backend] Cover views

Feature description

Need to implement cover/<song_id>/, cover/<song_id>/<instrument_id>/, cover/like/<pk>/ views

Screenshots / Additional context

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.