Code Review - saladlab onboarding

심준보·2023년 10월 23일
0

code review - sim jun bo

salad lab onboarding - [TodoList]

  • Frontend - angular
  • Backend - django

1. Frontend

  • / (home)
  • / singup
  • / login
  • / todo
  • / popup

2. Backend

  • / api
  • / user
  • / todo
  • 1. Frontend

  • ' /home '

1.1 home - '/ '

- img

  • 기능
  1. 페이지 이동

#. home 기능(1) - 페이지이동

요구사항

  1. 클릭하였을때 다른 페이지로 이동
  2. 경로 지정 : url <-> component

#1

  • home.components.ts

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.less'],
})
export class HomeComponent implements OnInit {
  constructor(private router: Router) {}

  signup() {
    this.router.navigate(['/signup']);
  }

  gologin() {
    this.router.navigate(['/login']);
  }

  ngOnInit(): void {}
}

mainpoint

  1. import {Router} from '@angular/router
  2. constructor(private router: Router){}
  3. this.router.navigate(['/singup'])


#2

  • app-routing.modules.ts

    [ routing을 관리하는 장소]

mainpoint

  1. import { routing 할 component } from "상대 경로";
  2. const routes: Routes -> 경로 지정
const routes: Routes = [
  { path: 'todo', component: TodoComponent },
  { path: 'home', component: HomeComponent },
  { path: 'signup', component: SignupComponent },
  { path: 'popup', component: PopupComponent },
  { path: 'login', component: LoginComponent },
  { path: '', pathMatch: 'full', component: HomeComponent },
];
  1. @NgModule -> imports,exports 둘다 지정
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})


  • ' /singup '

1.2 singup - ' /singup '

- img

  • 기능
  1. 회원가입
  2. 페이지 이동 - 'home' 의 페이지이동기능과 동일한 방법

#. signup 기능(1) - 회원가입

요구사항

  1. id , password값 input 에 입력
  2. 입력된 값을 서버로 보내기
  3. 서버로부터 받아온 값에 따라 경고문 or 로그인창으로 이동

#1

  • signup.components.ts

import { Component, OnInit } from '@angular/core';
import { ApiService } from '../service/api.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-signup',
  templateUrl: './signup.component.html',
  styleUrls: ['./signup.component.less'],
  providers: [ApiService],
})
export class SignupComponent implements OnInit {
  username = '';
  password = '';
  newusername = '';
  newpassword = '';
  SignupResult = '';

  constructor(private ApiServices: ApiService, private router: Router) {}

  // 데이터 잘 받는지 확인하는 작업
  SignupInputText() {
    console.log('username :', this.username);
    console.log('password :', this.password);
  }

  // 데이터 바깥으로 보내기 위한 함수

  PostInputText() {
    this.ApiServices.create<any>('user/signup', {
      username: this.username,
      password: this.password,
    }).subscribe(
      (json) => {
        console.log('result: ', json);
        this.SignupResult = json['result'];

        if (this.SignupResult == '0') {
          console.log('back값 확인', this.SignupResult);
          alert('회원가입이 완료되었습니다. 감사합니다.');
          this.gologin();
        } else if (this.SignupResult == '1') {
          alert('이미 사용중인 아이디입니다.');
        } else if (this.SignupResult == '2') {
          alert('빈 값을 채워주세요');
        } else console.log('미상 에러');

        // 값 저장하기 (회원가입 여부 성공 or 실패)
      },
      (error) => {
        console.log('error');
        console.log(this.username);
      }
    );
  }

mainpoint

  1. import {ApiService} from '../service/api.service';
  2. @Component({ ....
    providers: [ApiService],
    })
  3. constructor(private Apiservice:Apiservice..}
  4. PostInputText() - function

PostInputText() 함수

PostInputText() {
    this.ApiServices.create<any>('user/signup', {
      username: this.username,
      password: this.password,
    }).subscribe(
      (json) => {
        console.log('result: ', json);
        this.SignupResult = json['result'];

        if (this.SignupResult == '0') {
          console.log('back값 확인', this.SignupResult);
          alert('회원가입이 완료되었습니다. 감사합니다.');
          this.gologin();
        } else if (this.SignupResult == '1') {
          alert('이미 사용중인 아이디입니다.');
        } else if (this.SignupResult == '2') {
          alert('빈 값을 채워주세요');
        } else console.log('미상 에러');

        // 값 저장하기 (회원가입 여부 성공 or 실패)
      },
      (error) => {
        console.log('error');
        console.log(this.username);
      }
    );
  }
  • 서버로 데이터 요청하기 , 데이터보내기 (post)
this.ApiServices.create<any>('user/singup' ,{
  	username:this.username,
  	password:this.password,
  }
  1. ApiServices.create - post 기능

  2. create<'any'>

  3. username , password 라는 key로 서버에게
    this.username , this.password를 보낸다


  • 서버의 응답에 대한 값 처리
).subscribe(
      (json) => {
        console.log('result: ', json);
        this.SignupResult = json['result'];

        if (this.SignupResult == '0') {
          console.log('back값 확인', this.SignupResult);
          alert('회원가입이 완료되었습니다. 감사합니다.');
          this.gologin();
        } else if (this.SignupResult == '1') {
          alert('이미 사용중인 아이디입니다.');
        } else if (this.SignupResult == '2') {
          alert('빈 값을 채워주세요');
        } else console.log('미상 에러');

        // 값 저장하기 (회원가입 여부 성공 or 실패)
      },
      (error) => {
        console.log('error');
        console.log(this.username);
      }
    );
  1. subscribe() - 서버로부터 응답받기

  2. subscribe((json) => {...}, (error) => {...})
    -> json 응답이 오면 json {}안에 해당되는 코드 실행
    -> json 응답이 없을경우 , error {} 안에 코드 실행

  3. this.SignupResult = json["result"]

    -> SignupResult 에 담긴 서버의 응답에 따라 경고문 or login 창으로 이동


#2

  • api.sevice.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class ApiService {
  constructor(private http: HttpClient) {}

  public BASE_URL = 'http://localhost:8000/api/';

  get<T>(endPoint: string, params: {} = {}, headers: {} = {}): Observable<T> {
    const options = this.makeOption(params, headers);
    return this.http.get<T>(`${this.BASE_URL}${endPoint}`, options);
  }

  create<T>(
    endPoint: string,
    payload: {} = {},
    params: {} = {},
    headers: {} = {}
  ): Observable<T> {
    // const options = {
    //   params: params,
    //   headers: headers,
    // };

    return this.http.post<T>(`${this.BASE_URL}${endPoint}`, payload, params);
  }

  update<T>(
    endPoint: string,
    payload: {} = {},
    params: {} = {},
    headers: {} = {}
  ): Observable<T> {
    return this.http.put<T>(`${this.BASE_URL}${endPoint}`, payload, params);
  }

  delete<T>(
    endPoint: string,
    params: {} = {},
    headers: {} = {}
  ): Observable<T> {
    return this.http.delete<T>(`${this.BASE_URL}${endPoint}`, params);
  }

  makeOption(params: {} = {}, headers: {} = {}) {
    return {
      headers: headers,
      observe: 'body' as 'body',
      params: params,
      reportProgress: false,
      responseType: 'json' as 'json',
      withCredentials: true,
    };
  }
}

mainpoint

  1. import { HttpClient } from '@angular/common/http';
  2. import 'rxjs' ;
    -> 비동기적 쓰임을 하기 위해 위 쓰임으로 잘 구축된 rxjs를 사용하는 것
  3. import 'Injectable' ;
    -> 어디(components)에 쓸 것인지 범위를 정해주는 angular 데코레이터
  4. <'T'>
    -> 대명사 와 같은 ,
    -> 전달해주는 상자 역할
    -> ex) any,string,number etc..


  • ' /login '

1.3 login - ' / login '

- img

  • 기능
  1. 로그인
  2. session - localstorage 정보 저장
  3. 페이지 이동 - 'home' 의 페이지이동기능과 동일한 방법

#. login 기능(1) - 로그인

요구사항

  1. id , password값 input 에 입력
  2. 입력된 값을 서버로 보내기
  3. 서버로부터 받아온 값에 따라 경고문 or MainPage로 이동
  4. 로그인 성공 -> localstorage 에 정보 저장

#1

  • login.components.ts

import { Component, OnInit } from '@angular/core';
import { ApiService } from '../service/api.service';
import { Router } from '@angular/router';

// 로그인에서 세션 사용

import { SessionService } from '../service/session.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.less'],
  providers: [ApiService],
})
export class LoginComponent implements OnInit {
  loginusername = '';
  Userid = '';
  loginpassword = '';
  loginresult = false;
  key: string = '';

  constructor(
    private ApiServices: ApiService,
    private router: Router,
    private session: SessionService
  ) {}

  loginInputText() {
    this.ApiServices.create<any>('user/login', {
      loginusernames: this.loginusername,
      loginpasswords: this.loginpassword,
    }).subscribe(
      (json) => {
        console.log('result: ', json);
        this.loginresult = json['result'];
        this.Userid = json['resUserid'];

        if (this.loginresult == true) {
          //로그인 성공할시 session사용하여 localstorage에 저장되게 하자
          this.session.setInfo(this.Userid);

          this.GoMainPage();
          console.log('success_login', this.loginresult);
        } else {
          alert('아이디 또는 패스워드를 확인하세요.');
          console.log('fail_login', this.loginresult);

          // this.LoginError();
        }
      },
      (error) => {
        console.log('error');
      }
    );
  }

  GoMainPage() {
    this.router.navigate(['/todo']);
  }

  ngOnInit(): void {}
}

mainpoint

  1. import {SessionService} from '../service/session.service';
  2. constructor(private session: SessionService,...){ }
  3. loginInputText() 함수 - 로그인처리 & 정보저장

LoginInputText() 함수

loginInputText() {
    this.ApiServices.create<any>('user/login', {
      loginusernames: this.loginusername,
      loginpasswords: this.loginpassword,
    }).subscribe(
      (json) => {
        console.log('result: ', json);
        this.loginresult = json['result'];
        this.Userid = json['resUserid'];

        if (this.loginresult == true) {
          //로그인 성공할시 session사용하여 localstorage에 저장되게 하자
          this.session.setInfo(this.Userid);

          this.GoMainPage();
          console.log('success_login', this.loginresult);
        } else {
          alert('아이디 또는 패스워드를 확인하세요.');
          console.log('fail_login', this.loginresult);

          // this.LoginError();
        }
      },
      (error) => {
        console.log('error');
      }
    );
  }

  • 서버로부터 데이터 받아오는것 : 2가지
.subscribe(
      (json) => {
        console.log('result: ', json);
        this.loginresult = json['result'];
        this.Userid = json['resUserid'];
  1. loginresult - 로그인 결과(성공,실패)
  2. userid - 로그인 성공 시, 그 user의 고유 id

  • loginresult 값에 따른 처리
 if (this.loginresult == true) {
          //로그인 성공할시 session사용하여 localstorage에 저장되게 하자
          this.session.setInfo(this.Userid);

          this.GoMainPage();
          console.log('success_login', this.loginresult);
        } else {
          alert('아이디 또는 패스워드를 확인하세요.');
          console.log('fail_login', this.loginresult);

#. login 기능(2) - session - localstorage 정보 저장

  1. 로그인 성공

-> (1) this.session.setInfo(this.Userid);

-> (2) this.GoMainPage();

(1) session.setInfo()

-> user의 고유 id를 localstorage에 저장
-> 나중에 위 값을 통해 로그인 된 user에게 맞는 각각의 todolist를 불러온다.



#2

  • session.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class SessionService {
  constructor() {}

  setInfo(userid: string) {
    localStorage.setItem('USERNAME_ID', userid);
  }

  getInfo() {
    return localStorage.getItem('USERNAME_ID');
  }

  logOut() {
    localStorage.removeItem('USERNAME_ID');
  }
}

mainpoint

  1. setInfo() - 정보 저장
  2. getInfo() - 저장된 정보 사용하기
  3. logOut() - 저장된 정보 삭제

setInfo() 함수

setInfo(userid: string) {
    localStorage.setItem('USERNAME_ID', userid);
  }
  • key 는 'USERNAME_ID' 로 지정
  • Value 는 userid (string)

getInfo() 함수

getInfo() {
    return localStorage.getItem('USERNAME_ID');
  }
  • 'USERNAME_ID' (KEY) 에 지정된 값 사용

logOut() 함수

logOut() {
  localStorage.removeItem('USERNAME_ID');
}
  • 'USERNAME_ID' (KEY) 에 지정된 값 Localstorage에서 삭제


  • '/todo'

1.4 todo - ' / todo '

- img(1) - list 생성 전

- img(2) - list 생성 후

  • 기능
  1. 로그인 된 user에 맞는 list 불러오기
  2. 상태처리 - status에 따른 list 위치 변경
  3. duedate버튼 클릭시 , 정렬 상태 전환
  4. modify 버튼 클릭시 , 화면 전환 (updatemode)
  5. create 버튼 클릭시 , 화면 전환 (createmode) - 단순 페이지 이동 , 생략
  6. delete 버튼 클릭시 , 해당 list 삭제
  7. logout 버튼 클릭시 , storage정보 제거 후 로그아웃

#1

  • todo.components.ts

import { Component, OnInit } from '@angular/core';
import { ApiService } from '../service/api.service';
import { Router } from '@angular/router';

import { SessionService } from '../service/session.service';

@Component({
  selector: 'app-todo',
  templateUrl: './todo.component.html',
  styleUrls: ['./todo.component.less'],
  providers: [ApiService],
})
export class TodoComponent implements OnInit {
  todomaining = '';
  todomaindone = '';

  todoidpk = '';

  todoidstatus = '';

  // todo 상태 결정변수s
  originalstatus = true;

  // popup상태 결정변수s
  createpopup = false;
  updatepopup = true;

  // popup 에게 넘겨줄 현재 todo데이터
  transPopupStatus = false;
  transPopupTitle = '';
  transPopupContent = '';
  transPopupDuedate = '';
  transPopupCreate = '';
  transPopupUpdate = '';

  // popup 넘겨줄때 데이터가공

  processPopupduedate = '';
  processPopupduedate2 = '';

  processPopupcreate = '';
  processPopupcreate2 = '';

  processPopupupdate = '';
  processPopupupdate2 = '';

  // session 사용할 변수
  useridtd = this.session.getInfo();

  // duedate 정렬 버튼 변수
  duedatebtnon = '1';

  // button result (무한변경에 사용)
  resultduedatebtn1 = 0;
  resultduedatebtn2 = 0;

  constructor(
    private apiService: ApiService,
    private router: Router,
    private session: SessionService
  ) {}

  // todo 생성 팝업으로 이동
  gotodopopup() {
    this.router.navigate(['/popup']);
  }

  // todolist db에 정보 가져오는 함수 (GET)

  getToDoPlan() {
    this.apiService
      .create<any>('todo/sendtodo', {
        UserIdtd: this.useridtd,
        duedatebtn: 0,
      })
      .subscribe(
        (json) => {
          console.log('result_todo_data:', json);
          this.todomaining = json['tdmaining'];
          console.log('tdmding', this.todomaining);
        },
        (error) => {
          console.log('error');
        }
      );
  }
  getToDoDone() {
    this.apiService
      .create<any>('todo/sendtodo2', {
        UserIdtd: this.useridtd,
        duedatebtn: 0,
      })
      .subscribe(
        (json) => {
          console.log('result_todo_data:', json);
          this.todomaindone = json['tdmaindone'];
          console.log('tdmddone', this.todomaindone);
        },
        (error) => {
          console.log('error');
        }
      );
  }

  // due date -> 이른 순 또는 늦은순에 따라 정렬하기 || default -> 이른순  , 클릭시 반대값으로 정렬
  lineupDueDatePlan() {
    this.apiService
      .create<any>('todo/sendtodo', {
        UserIdtd: this.useridtd,
        duedatebtn: 1,
      })
      .subscribe(
        (json) => {
          console.log('successduedate');
          this.todomaining = json['tdmaining'];
        },
        (error) => {
          console.log('duedateerror');
        }
      );
  }
  lineupDueDateDone() {
    this.apiService
      .create<any>('todo/sendtodo2', {
        UserIdtd: this.useridtd,
        duedatebtn: 1,
      })
      .subscribe(
        (json) => {
          console.log('successduedate');
          this.todomaindone = json['tdmaindone'];
        },
        (error) => {
          console.log('duedateerror');
        }
      );
  }

  // btn의 값이 짝수인지 홀수인지에 따라 다른 정렬함수 호출
  resultplanduedate() {
    this.resultduedatebtn1 += 1;
    if (this.resultduedatebtn1 % 2 == 0) {
      this.getToDoPlan();
    } else {
      this.lineupDueDatePlan();
    }
    console.log(this.resultduedatebtn1);
  }

  resultdoneduedate() {
    this.resultduedatebtn2 += 1;
    if (this.resultduedatebtn2 % 2 == 0) {
      this.getToDoDone();
    } else {
      this.lineupDueDateDone();
    }
    console.log(this.resultduedatebtn2);
  }

  // id 인자값으로 html 파일의 (tdmd[0]을 받는다)
  deleteToDo(id: string) {
    console.log(id);
    this.todoidpk = id;
    this.apiService
      .create<any>('todo/delete', {
        todopkid: this.todoidpk,
      })
      .subscribe(
        (json) => {
          console.log('gooddelete');
          this.getToDoPlan();
          this.getToDoDone();
        },
        (error) => {
          console.log('error');
        }
      );
  }

  // modifybutton을 클릭하였을때 ,
  // 1.popup창으로 전환,

  modifyToDo(id: string) {
    console.log('modify', id);
    this.todoidpk = id;
    this.originalstatus = false;
    this.postToDoPopup();
  }

  // status 버튼 check 시 status값 변환

  checkstatus(id: string) {
    this.todoidstatus = id;
    console.log('checkstatus', id);
    this.apiService
      .update<any>('todo/statusmodify', {
        statusid: this.todoidstatus,
      })
      .subscribe(
        (json) => {
          console.log('status success');
          location.reload();
        },
        (error) => {
          console.log('error');
        }
      );
  }

  //페이지 로딩될떄마다 db에서 todo data불러오기

  backtodo() {
    this.originalstatus = true;
  }

  //todo 에서 modify버튼 클릭시 해당 todoid에 맞는 값 back에 전송

  postToDoPopup() {
    this.apiService
      .create<any>('todo/sendtodopopup', {
        tdpopupid: this.todoidpk,
      })
      .subscribe(
        (json) => {
          console.log('popupresult', json);
          this.transPopupStatus = json['tdcurrentstatus'];
          this.transPopupTitle = json['tdcurrenttitle'];
          this.transPopupContent = json['tdcurrentcontent'];
          this.transPopupDuedate = json['tdcurrentduedate'];
          this.transPopupCreate = json['tdcurrentcreate'];
          this.transPopupUpdate = json['tdcurrentupdate'];

          //  한번에 데이터 가공  - duedate
          this.processPopupduedate =
            this.transPopupDuedate.substring(0, 10) +
            ' ' +
            this.transPopupDuedate.substring(11, 16);

          // 두개의 변수를 이용한 데이터 가공  - createdate, updatedate

          this.processPopupcreate = this.transPopupCreate.substring(0, 10);
          this.processPopupcreate2 = this.transPopupCreate.substring(11, 16);

          this.processPopupupdate = this.transPopupUpdate.substring(0, 10);
          this.processPopupupdate2 = this.transPopupUpdate.substring(11, 16);

          console.log('success', this.transPopupStatus);
        },
        (error) => {
          console.log('error');
        }
      );
  }

  // Log Out -> session  정보값 remove , 이동하기 -> 홈으로

  logout() {
    this.session.logOut();
    this.router.navigate(['']);
  }

  ngOnInit(): void {
    this.getToDoPlan();
    this.getToDoDone();
  }
}

#. todo 기능(1) - 로그인 된 user에 맞는 list 불러오기

요구사항

  1. session에 있는 userid를 변수에 저장 하여 서버에 넘겨주기
useridtd = this.session.getInfo();
.
.
.
getToDoPlan() {
    this.apiService
      .create<any>('todo/sendtodo', {
        UserIdtd: this.useridtd,
        duedatebtn: 0,
      })
  1. '/todo'url에 올때마다 gettododb() 함수 작동

    ngOnInit() -> "라이프 사이클 " - 초기화기능
    #. 유사 -> constructor()

  ngOnInit(): void {
    this.getToDoPlan();
    this.getToDoDone();
  }
  1. plan / done에 대한 함수 따로 작성

    -> 따로 함수를 작성한 이유중 가장 큰 것은
    duedate btn에 따라 정렬될때 plan 일때와 done일때 따로 작용해야 되기 때문이다.
    그렇기에 함수를 따로 작성하였고 백엔드에서도 api를 세분화 시켰다.

getToDoPlan() {
    this.apiService
      .create<any>('todo/sendtodo', {
        UserIdtd: this.useridtd,
        duedatebtn: 0,
      })
      .subscribe(
        (json) => {
          console.log('result_todo_data:', json);
          this.todomaining = json['tdmaining'];
          console.log('tdmding', this.todomaining);
        },
        (error) => {
          console.log('error');
        }
      );
  }
  getToDoDone() {
    this.apiService
      .create<any>('todo/sendtodo2', {
        UserIdtd: this.useridtd,
        duedatebtn: 0,
      })
      .subscribe(
        (json) => {
          console.log('result_todo_data:', json);
          this.todomaindone = json['tdmaindone'];
          console.log('tdmddone', this.todomaindone);
        },
        (error) => {
          console.log('error');
        }
      );
  }

#. todo 기능(2) - 상태처리 : status에 따른 list 위치 변경

요구사항

  1. status 버튼 - 클릭시 이미지 변경

    img 1. - plan mode

    img 2. - Done mode

  2. checkstatus() 함수 사용 - status 이미지 클릭시
checkstatus(id: string) {
    this.todoidstatus = id;
    console.log('checkstatus', id);
    this.apiService
      .update<any>('todo/statusmodify', {
        statusid: this.todoidstatus,
      })
      .subscribe(
        (json) => {
          console.log('status success');
          location.reload();
        },
        (error) => {
          console.log('error');
        }
      );
  }

#. todo.component.html(일부)

<img (click)="checkstatus(tdmding[0])" src="assets/image/circle2.png"
                    style="width:36px; margin-left:33px; margin-top:10px; cursor: pointer;">

status img : 클릭시 , checkstatus()함수에 고유 todoid를 인자로 넣어 서버에 전달

#. todo 기능(3) - duedate버튼 클릭시 , 정렬 상태 전환

  1. Duedatebtn 클릭시 , plan , done 각각에 맞게 정렬 상태 전환
  2. 기본상태 - duedate 오름차순 기준으로 list들이 위에서 아래로 나열
  3. resultplanduedate() - btn 변수의 값 저장 및 값이 홀수인지 짝수인지에 따라 다른 함수 처리
  4. getToDoPlan() - 오름차순 정렬 함수 (default)
  5. lineupDueDatePlan() - 내림차순 정렬 함수 (기본값과 반대로)

resultplanduedate() / this.resultduedatebtn = '?'

  • 짝 -> getToDoPlan()
  • 홀 -> lineupDueDatePlan()

#. todo 기능(4) - modify 버튼 클릭시 , 화면 전환 (updatemode)

  1. modify 버튼 클릭시 -> 화면 전환

img . modify

  1. todo의 html은 두가지 버전으로 관리된다
  • originalstate = true (default ) - 일반적인 todo화면
  • originalstate = false - 수정버튼 클릭시 popup selector사용

#. todo.component.html(일부)

 <ng-container *ngIf="!originalstatus">

      <!-- 앞에 것이 자식 컴포넌트 변수 , 뒤에 것이 부모 컴포넌트 변수 -->
      <app-popup (originalstate)="backtodo()" [todoid]="todoidpk" [createmode]="createpopup" [updatemode]="updatepopup"
        [todocurrentstatus]="transPopupStatus" [todocurrenttitle]="transPopupTitle"
        [todocurrentcontent]="transPopupContent" [todocurrentduedate]="processPopupduedate"
        [todocurrentduedate2]="processPopupduedate2" [todocurrentcreate]="processPopupcreate"
        [todocurrentcreate2]="processPopupcreate2" [todocurrentupdate]="processPopupupdate"
        [todocurrentupdate2]="processPopupupdate2"></app-popup>


 </ng-container>
 <ng-container *ngIf="originalstatus">
   .
   .
   .
  1. @Input 데코레이터 사용

    • ipnut 데코레이터는 자식이 부모의 데이터를 사용하고 싶을때 사용하는 것이다.
  • 부모(todo)로부터 자식(popup)이 써야되는 데이터가 있기때문에

  • 부모 html에서 쓰임을 작성 ,

  • 앞이 자식 , 뒤가 부모

    #. ex)

    [todoid]="todoidpk"

#. todo 기능(5) - create버튼 클릭시 , 화면 전환

  • this.router.navigate(['/popup']) 사용

#. todo 기능(6) - delete 버튼 클릭시 , 해당 list 삭제

img . delete

  1. deleteToDo(id:string)
deleteToDo(id: string) {
    console.log(id);
    this.todoidpk = id;
    this.apiService
      .create<any>('todo/delete', {
        todopkid: this.todoidpk,
      })
      .subscribe(
        (json) => {
          console.log('gooddelete');
          this.getToDoPlan();
          this.getToDoDone();
        },
        (error) => {
          console.log('error');
        }
      );
  }
  • delete버튼 클릭시, 해당 todoid값 서버에게 전달
  • 서버에서 삭제 후 , json응답이 원활할 경우 ,
    다시 getToDoPlan() , getToDoDone() 함수 호출

#. todo 기능(7) - logout 버튼 클릭시 , storage정보 제거 후 '/'(home) 으로 이동

img . logout

  1. logout()
  logout() {
    this.session.logOut();
    this.router.navigate(['']);
  }
  • this.session.logOut()
  logOut() {
    localStorage.removeItem('USERNAME_ID');
  }
   

session.service.ts / logOut() 을 사용한 것
removeItem() 으로 key값 삭제

  • this.router.navigate([''])

    : session제거 후 홈으로 이동



1.5 popup - ' / popup '

- img(1) - createmode

- img(2) - updatemode

  • 기능
  1. createmode - 새로운 list 에 맞는 값 서버로 전달
  2. createmode - material : datetimepicker
  3. updatemode - list에 맞는 값 placeholder에 지정해주기
  4. updatemode - list에 변경된 값 서버로 전달

#1

  • popup.components.ts

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ApiService } from '../service/api.service';
import { Router } from '@angular/router';
import { TodoComponent } from '../todo/todo.component';

import { SessionService } from '../service/session.service';

@Component({
  selector: 'app-popup',
  templateUrl: './popup.component.html',
  styleUrls: ['./popup.component.less'],
})
export class PopupComponent implements OnInit {
  @Input() todoid = '';

  // popup 역할 - 1.create , 2. update  || default 는 createmode
  @Input() createmode = true;
  @Input() updatemode = false;

  // popup - modify모드일때 현재값 불러오기 - 부모(todo)에게 전달받아
  @Input() todocurrentstatus = false;
  @Input() todocurrenttitle = '';
  @Input() todocurrentcontent = '';
  @Input() todocurrentduedate = '';
  @Input() todocurrentduedate2 = '';
  @Input() todocurrentcreate = '';
  @Input() todocurrentcreate2 = '';
  @Input() todocurrentupdate = '';
  @Input() todocurrentupdate2 = '';

  

  // /todo 기본으로 돌아가기 위한  , 자식에서 부모로 상태값 넘기기 위한 변수
  @Output() originalstate = new EventEmitter<boolean>();

  // create mode 일때 변수

  todostatus = false;
  todotitle = '';
  todocontent = '';
  tododuedate = '';

  // modify mode 일때 변수
  todomdstatus = false;
  todomdtitle = '';
  todomdcontent = '';
  todomdduedate = '';

  // session 에 저장되어있는 user_id를 사용해서 todocreate 할때 기입할 변수
  userid = '';

  // 수정버튼눌렀을때 사용 변수
  todopopupdata = '';

  data = Date();

  constructor(
    private ApiServices: ApiService,
    private router: Router,
    private session: SessionService
  ) {}

  // tododata check  함수 -> 확인  ok
  checktododata() {
    console.log('status:', this.todostatus);
    console.log('title:', this.todotitle);
    console.log('content:', this.todocontent);
    console.log('duedata:', this.tododuedate);
  }

  // popup창 취소 버튼 구현

  popupcancle() {
    this.router.navigate(['/todo']);
  }

  backtoorigin(value: boolean) {
    this.originalstate.emit(value);
  }

  // todo db에 data 보내기

  PostToDoData() {
    console.log('session result', this.session.getInfo());
    console.log('duedate 실험', this.tododuedate);

    this.ApiServices.create<any>('todo/create', {
      userids: this.session.getInfo(),
      tdstatus: this.todostatus,
      tdtitle: this.todotitle,
      tdcontent: this.todocontent,
      tdduedate: this.tododuedate,
    }).subscribe(
      (json) => {
        console.log('good');
        this.router.navigate(['/todo']);
      },
      (error) => {
        console.log('error');
        alert('필수 항목을 입력해주세요.');
      }
    );
  }

  // todo 해당 id에 맞는 db 가져오기

  // todo db 수정하기

  updateToDoData() {
    var updatetime = new Date();

    this.ApiServices.update<any>('todo/modify', {
      tdmdid: this.todoid,
      tdmdstatus: this.todomdstatus,
      tdmdtitle: this.todomdtitle,
      tdmdcontent: this.todomdcontent,
      tdmdduedate: this.todomdduedate,
    }).subscribe(
      (json) => {
        console.log('success');
        console.log('업데이트시간', updatetime);

        this.backtoorigin(true);
        // reload방법으로 , 수정시 새로고침하여 db값 가져오기
        location.reload();
      },
      (error) => {
        console.log('error');
      }
    );
  }

  // create창에서 status상태 변경 btn 구현

  statusbtncreate() {
    if (this.todostatus == false) {
      this.todostatus = true;
    } else {
      this.todostatus = false;
    }
  }

  statusbtnupdate() {
    if (this.todomdstatus == false) {
      this.todomdstatus = true;
    } else {
      this.todomdstatus = false;
    }
  }

  // calendar 구현

  ngOnInit(): void {}
}

mainpoint

  1. popup 역할
    • . createmode
    • . updatemode
 // popup 역할 - 1.create , 2. update  || default 는 createmode
  @Input() createmode = true;
  @Input() updatemode = false;
  • 기본값은 createmode가 true, updatemode가 false로 create popup창이 기본이다.
  • 하지만, todo.component.ts/modify 버튼 클릭시 @Input( )를 사용하여 createmode -> false , updatemode -> true 처리를 한다.
    이렇게 하여, 팝업 상태는 updatemode로 변동된다.

#. popup.component.html(일부)


  <ng-container *ngIf="updatemode">
    <!-- 부모 자식 데이터 전달 테스트 -->


    <div class="realpopups2">
      <div class="infoboxs2">


        <div class="titlebox2">
          <input class="Titletext2" [(ngModel)]="todomdtitle" type="text" placeholder={{todocurrenttitle}} />
        </div>
        .
        .
        .
        
  1. *ngIf
  • *ngIf = " x "
    x값이 true(boolean)상태일때만, <'ng-container'> 안에 있는 html요소 들이 화면에 나타난다.
  • 이를 활용하여 , createmode & updatemode를 관리한다.

#. popup.component.html(일부)

 <!-- new -material -date&time -->
          <div class="datetime">
            <mat-form-field>
              <input matInput type="datetime-local" [(ngModel)]="tododuedate">>
            </mat-form-field>
          </div>
 <!-- /new -material -date&time -->
  1. material - datepicker 소스 사용

  • material - datepicker 사용
  1. npm - angular 버전에 맞는 material 설치
    • npm site 에서 찾아보는 것이 정확(지원버전도 나와있다)
  2. 상속되어있는 module.ts에 필요사항 import
    • popup.component는 todo.module.ts에 상속되어있다.

      import { MatInputModule } from '@angular/material/input';
      import { MatFormFieldModule } from '@angular/material/form-field';
  3. 필요한 material-datepicker 소스 사용하기
    • date , time 둘다 필요하기에 , 둘다 체크할 수 있고 한번에 datetime값으로 들어가며, 한국 표준 시간으로 되어있는 소스를 찾아 사용함
  4. placeholder 사용 - 기존의 list 구성 값 보여주기


        <div class="duedatebox2">
          <div>
            <p style="margin:20px; font-size: 20px;">Due Date : </p>
          </div>
          <div class="duedateinputbox2">
            <input class="DueDatetext2" [(ngModel)]="todomdduedate" type="text" placeholder={{todocurrentduedate}} />
          </div>
        </div>
  • 부모(todo)에게서 받아온 데이터(제목,날짜,자세한내용 etc.)등을 popup-updatemode일때 placeholder를 사용하여 보여준다


  • 2. Backend

    • '/api'

      • settings.py

      • urls.py


    • '/user'

      • views.py

      • urls.py

      • models.py

      • apps.py


    • '/todo'

      • views.py

      • urls.py

      • models.py

      • apps.py

      
  • '/api'

  • '/api/settings.py'

#1. settings.py

#mainpoint1
        
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'user',
    'todo',


    'corsheaders',

]
        
#mainpoint2
        
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    
]
        
#mainpoint3
        
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}
  
#mainpoint4

CORS_ORIGIN_WHITELIST = ['http://127.0.0.1:4200' ,'http://localhost:4200']
CORS_ALLOW_CREDENTIALS = True
        
#mainpoint5
        
APPEND_SLASH=False
  • mainpoint

1. INSTALLED_APPS

  • 앱을 생성할 경우, 생성한 앱을 settings.py에 등록을 해줘야한다.
  • <앱의 폴더명> 으로 / ex) todo 앱이면 -> 'todo' 로 기입
  • 추후, python manage.py makemigrations / python manage.py migrate 사용할때 장고에서 해당 앱의 모델을 인식할 수 있다.
          

2. MIDDLEWARE/'django.middleware.csrf.CsrfViewMiddleware'

  • csrf 공격을 방어해주는 역할을 한다.
     *csrf :웹 어플리케이션 취약점 중 하나로 인터넷 사용자(희생자)가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 만드는 공격
      
  • 하지만 , 이로 인해 요청자체가 불가하기 때문에 이를 주석처리해준다.
      

3. DATABASES

  • 데이터베이스 연결 설정
  • 장고에서는 기본적으로 'sqlite3'를 사용하도록 되어있다.
  • 본 서버는 'sqlite3' 사용

4. CORS_ORIGIN_WHITELIST

CORS : Cross Origin Resource Sharing

  • CORS 문제는 다른 도메인의 서버로부터 요청이 들어왔을 때, 헤더에 접근을 허락하는 내용이 없으면 발생한다

  • 접근 허락을 위해(django-cors-headers 설치)

1.
        
INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]
        
2.
        
# Corsmiddleware가 Commonmiddleware보다 위에 설정
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware', 
    'django.middleware.common.CommonMiddleware', 
    ...
]
        
3.
        
CORS_ORIGIN_WHITELIST = ['http://127.0.0.1:4200' ,'http://localhost:4200']
        
  • CORS_ORIGIN_WHITELIST 에 허락하고 싶은 포트를 설정해준다.
  • '/api'

  • '/api/urls.py'

#2. urls.py

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('api/', include([
        path('todo/', include('todo.urls')),
        path('admin/', admin.site.urls),
        path('user/', include('user.urls') )
    
    ])),
]
  • api/urls.py 에서는 전체적인 라우팅을 정의해준다.
  • 백에서의 라우팅은 "특정url주소" 로 접근하였을때 그 주소에 맞는
    함수 or 클래스를 호출해주는 것을 말한다.
  • 예로, todo/ , include('todo.urls') 는 todo/로 접근하였을때 todo에 속해있는 url을 따를 것이라는 것이다.
  • root는 localhost:8000/ 이니,
    todo/ 에 접근하기 위한 전체적인 주소는 localhost:8000/api/todo/가 되는 것이다.
        
  • '/user'

  • user table 관리 및 user 관련 함수 생성

  • '/user/models.py'

#1. user/models.py

class UserSignup(models.Model):
  id = models.IntegerField(primary_key=True)
  user_name = models.CharField(max_length=50)
  password = models.CharField(max_length=100)
  created_at = models.DateTimeField(auto_now_add=True)
  • user model은 4개의 필드
  • id는 int , username과 password는 char, created_at은 datetime
      
  • '/user/views.py'

    • views.signup

    • views.login

#1. user/views.py


# 1. 회원가입
# user/signup
def signup(request):
  
  if request.method == 'POST':

    # POST처리 성공여부 확인
    print("signup_success")

    # try:
 
    #어느 곳에 데이터가 들어가있는지 확인(body or POST)
    print('body',request.body)
    print('post',request.POST)


    #프론트에서 데이터 받아서 저장
    SignupPayload = json.loads(request.body)
    print("payload" , SignupPayload)
    username = SignupPayload["username"]
    password = SignupPayload["password"]


    print("test", username , password)

    # ---회원삭제---

    # deletes = UserSignup.objects.all()
    # deletess = deletes.delete()
   

    # 1. 회원가입시 user_name 중복체크

    # 1.1 현재 table의 username 모두 가져오기
    usernames = UserSignup.objects.all().values_list('user_name' , flat = True)
    print("현재 usrname:", usernames)


    # ---프론트에게 던져줄 값---

    # -> 0,1 에서 null값 처리를 위해 경우를 세분화 (성공,중복에러,null에러)

    success = {
      'result': '0'

    }

    DuplicationFail = {
      'result' : '1'
    }

    NullFail ={
      'result' : '2'
    }

    # print("프론트값전달" , success, DuplicationFail )

    # 1.2.1  -> null값은 불통처리

    if (username == '') or (password == ''):
      return JsonResponse(NullFail)
    
    # 1.2 중복체크 통과 -> 저장  , 불통 -> 경고메세지
    for i in usernames:
      if i == username:
          # 불통 -> 경고메세지 실행 및 http 오류 처리
          print("---error: 사용자 정보가 중복으로 존재합니다---")
          return JsonResponse(DuplicationFail )
    # 통과 -> 저장 및 확인메세지 출력
    new_user = UserSignup.objects.create(user_name= username , password =password )
    print("---success: 저장이 되었습니다---")
    return JsonResponse(success )


    # 예외처리
    # except Exception as e:
    #   print("error", e)

      
   

# 2. 로그인
# user/login

# 먼저, username부터 확인하고 성공시 다음 orm 진행 
# 통과 할시, password 값 확인 후 로그인 처리

def login(request):
  
  if request.method == 'POST':

    print("로그인 통신")

    #0. front에서 사용자가 기입한 username과 password값 

    LoginPayload = json.loads(request.body)
    print("front data: ", LoginPayload)
    LoginUsername = LoginPayload["loginusernames"]
    print("사용자입력id : " ,LoginUsername)
    LoginPassword = LoginPayload["loginpasswords"]
    print("사용자입력pw : " ,LoginPassword)

    #1.DB username 확인 

    UsernameSet = UserSignup.objects.all().values_list("user_name" , flat = True)
    print(UsernameSet)



    
    # 1단계, username 일치하는지 확인

    loginusernamefail = {
      "result" : False
    }

    x =0 
    for i in UsernameSet:
      if i == LoginUsername:
        x += 1
        print("x", x)
      else:
        print("bad")
      
    if x ==0:
      print("username fail _ firstfail")
      return JsonResponse(loginusernamefail)
    



    #2.DB에서 해당 user -> password 확인

    Passwordreal = UserSignup.objects.filter(user_name = LoginUsername).values_list("password", flat= True)
    print("아사람의 패스워드: " ,Passwordreal[0])

    #2-2 -> session이용하기 위한 해당 username에 대한 userid값 넘겨주기
    Userids = UserSignup.objects.filter(user_name = LoginUsername).values("id")

    print("USERID:" , Userids)




    # 2단계, username 일치 통과한 유저는 password 일치하는지 확인

    loginsuccess = {
      "result" : True,
      "resUserid" : Userids[0]["id"]
    }

    loginpasswordfail = {
      "result" : False
    }

    
    # 수정  -> passwordset -> passwordreal(하나의 값)
    if Passwordreal[0] == LoginPassword:
        return JsonResponse(loginsuccess )
    return JsonResponse(loginpasswordfail)
     
  • 1. POST - user/signup

    • 회원가입

        1. 사용자가 입력한 username과 password를 받는다
        1. 중복 username이 생기면 안되기에, userdb에 있는 username값을 전부 가져온다.
        1. 회원가입 성공여부를 결정한다.
      • 3.1 사용자가 username 또는 password중 빈값으로 기입한것이 있는지 확인한다.
      • 3.2 사용자가 기입한 username이 기존 db에 있는지 확인한다.
      • 3.3 회원가입 성공여부를 결정한다.

1. 사용자가 입력한 username과 password를 받는다

SignupPayload = json.loads(request.body)
username = SignupPayload["username"]
password = SignupPayload["password"]

request.body

  • request.body 로 프론트의 데이터가 담겨온다
  • request.post에는 데이터가 담겨지지 않았다.

json.load()

  • json 은 javascript object notation으로 키-값으로 이루어진 object이다.
  • json 타입과 python은 1:1 매칭되며 아래와 같다.

프론트에서 받아온 - username , password

  • dictionary형태로 역변환 시켰기에 ,
    username = SignupPayload["username"] 으로 값 저장한다.

2. 중복 username이 생기면 안되기에, userdb에 있는 username값을 전부 가져온다.

usernameset = UserSignup.objects.all().values_list('user_name' , flat = True)
  • orm 사용
    • UserSignup (table) 에서 모든 값중 'user_name' 필드값만 가지고 온다.
    • values()는 Dict를 반환하고, values_list()는 Tuple을 반환
    • username 사용 가능 확인을 위해선 , 리스트 형태가 필요하다고 판단
    • values_list( , flat = True) -> list형태 반환

// 3. 회원가입 성공여부를 결정한다.

3.1 사용자가 username 또는 password중 빈값으로 기입한것이 있는지 확인한다.

        
NullFail ={
      'result' : '2'
    }

        
if (username == '') or (password == ''):
      return JsonResponse(NullFail)
  • ' ' 가 빈값처리된 것.
    • 둘중 하나라도 빈값이면 오류 데이터 전송

3.2 사용자가 기입한 username이 기존 db에 있는지 확인한다.

        
success = {
      'result': '0'

    }

    DuplicationFail = {
      'result' : '1'
    }

        
for i in usernameset:
      if i == username:
          # 불통 -> 경고메세지 실행 및 http 오류 처리
          print("---error: 사용자 정보가 중복으로 존재합니다---")
          return JsonResponse(DuplicationFail )
    # 통과 -> 저장 및 확인메세지 출력
new_user = UserSignup.objects.create(user_name= username , password =password )
print("---success: 저장이 되었습니다---")
return JsonResponse(success )
  • .create 사용하여 데이터 저장
    • UserSignup.objects.create(user_name = username ,..)
  • 2. POST - user/login

    • 로그인

        1. 사용자가 입력한 username(id)와 password를 받는다
        1. 로그인의 성공여부를 결정한다.
      • 2.1 사용자가 입력한 username이 실제db에 존재하는지 확인
      • 2.2 2.1통과시 사용자가 입력한 password가 db에 존재하는 입력한 username의 password와 일치하는지 확인
        1. 로그인 성공시 session에 저장될 사용자의 고유 id를 프론트에 전달해준다.

1.사용자가 입력한 username(id)와 password를 받는다

    -> 회원가입 로직과 동일

// 2.로그인의 성공여부를 결정한다

  • 먼저 , username이 일치하는지 확인하고! 다음 단계로 이동, 없을 경우 그 상태에서 바로 fail return 해주기

  • 윗 단계가 통과 될시! , 실제 db 해당 password불러오고 일치하는지 확인

    2.1 사용자가 입력한 username이 실제db에 존재하는지 확인

      UsernameSet = UserSignup.objects.all().values_list("user_name" , flat = True)
      print(UsernameSet)
    
      
      # 1단계, username 일치하는지 확인
    
      loginusernamefail = {
        "result" : False
      }
    
      x =0 
      for i in UsernameSet:
        if i == LoginUsername:
          x += 1
          print("x", x)
        else:
          print("bad")
        
      if x ==0:
        print("username fail _ firstfail")
        return JsonResponse(loginusernamefail)
      

    2.2 사용자가 입력한 password가 db에 존재하는 입력한 username의 password와 일치하는지 확인

           
       loginsuccess = {
         "result" : True,
         "resUserid" : Userids[0]["id"]
       }
    
       loginpasswordfail = {
         "result" : False
       }
    
       
       # 수정  -> passwordset -> passwordreal(하나의 값)
       if Passwordreal[0] == LoginPassword:
           return JsonResponse(loginsuccess )
       return JsonResponse(loginpasswordfail)
        
    		```

3. 로그인 성공시 session에 저장될 사용자의 고유 id를 프론트에 전달해준다.

Userids = UserSignup.objects.filter(user_name = LoginUsername).values("id")
 
loginsuccess = {
      "result" : True,
      "resUserid" : Userids[0]["id"]
    }
  • filter사용
  • 이번엔 values사용
  • values를 사용했기에 , Userids[0]["id"] 로 값 저장


  • '/todo'

  • todo table 관리 및 todo 관련 함수 생성

  • '/todo/models.py'

#1. todo/models.py

        
class TodoModel(models.Model):
  id = models.IntegerField(primary_key=True)
  user_id = models.IntegerField(null=True)
  status = models.BooleanField(null=False)
  title = models.CharField(max_length=64,null=False)
  content = models.CharField(max_length=300)
  due_date = models.DateTimeField(null=False)
  created_at = models.DateTimeField(auto_now_add=True)
  updated_at = models.DateTimeField(auto_now=True)
        
  • 총 8개의 field 로 구성
  • auto_now_add 와 auto_now ?

    - datetimefield 내에 있는 것으로, 둘다 현재 시간으로 db에 insert가 되지만 ,

    1. auto_now_add는 처음 insert 될 시점에만 현재 시간으로 기입되고 추후에는 되지 않는다. 그래서 '최초생성일자'(created_at) 와 같은 field에 적용을 하고,

    2. auto_now 는 장고 모델이 save될때마다 현재 날자로 수정이 된다. 그래서 '최종수정일자'(updated_at)와 같은 field에서 적용된다.

      
  • '/todo/views.py'

    • views.sendtododb

    • views.sendtododb2

    • views.sendtodopopup

    • views.todocreate

    • views.tododelete

    • views.todomodify

    • views.statusmodify

#1. todo/views.py


# todo/sendtodo   -> plan에 대한 
def sendtododb(request):

    if request.method == 'POST':

        useridPayload  = json.loads(request.body)
        ThisUserId = useridPayload['UserIdtd']
        print("get_success_sendtododata")


        #due_date정렬을 여기서 관리를 해줘야할거같다.
        #button - on -> order_by().reverse() 사용
        #button - off -> order_by() 만 사용

        button = useridPayload['duedatebtn']
        print("duedate" , button)

        # 정렬에 -> order_by() , reverse() 사용 
        if button == 0:
            TodoDBing = list(TodoModel.objects.order_by('due_date').filter(user_id=ThisUserId, status = False).values_list('id','status','title','content','due_date' ))
      
        
        else :
            TodoDBing = list(TodoModel.objects.order_by('due_date').reverse().filter(user_id=ThisUserId, status = False).values_list('id','status','title','content','due_date' ))
       


        print("현재 진행중: ", TodoDBing)
    
        data = {
            'tdmaining' : TodoDBing,
        }

        return JsonResponse(data)
    
# todo/sendtodo2  -> done에 대한

def sendtododb2(request):

    if request.method == 'POST':

        useridPayload  = json.loads(request.body)
        ThisUserId = useridPayload['UserIdtd']
        print("get_success_sendtododata")


        #due_date정렬을 여기서 관리를 해줘야할거같다.
        #button - on -> order_by().reverse() 사용
        #button - off -> order_by() 만 사용

        button = useridPayload['duedatebtn']
        print("duedate" , button)

        if button == 0:
            TodoDBdone = list(TodoModel.objects.order_by('due_date').filter(user_id=ThisUserId,  status = True).values_list('id','status','title','content','due_date' ))
        
        else :
            TodoDBdone = list(TodoModel.objects.order_by('due_date').reverse().filter(user_id=ThisUserId,  status = True).values_list('id','status','title','content','due_date' ))


        print("완료 : ", TodoDBdone)

        data = {
            'tdmaindone' : TodoDBdone,
        }

        return JsonResponse(data)
    

# todo/sendtodopopup
# todopopup - 해당 id 값에 맞는 값들 전송

def sendtodopopup(request):

    if request.method == 'POST':

        print("get_success_sendpopup")

        # front에서 보낸 todo id 값 
        popupidPayload = json.loads(request.body)
        tdid = popupidPayload['tdpopupid']
        print("front에서 넘겨준 tododid: " , tdid)

        # todoDB 에서 usetdid와 동일한 값의 행 추출

        tddata = TodoModel.objects.filter(id = tdid).values()
        

        # front에 넘겨줄 data

        todocurrentdata = {
            'tdcurrentstatus' : tddata[0]['status'] ,
            'tdcurrenttitle' : tddata[0]['title'],
            'tdcurrentcontent' : tddata[0]['content'],
            'tdcurrentduedate' : tddata[0]['due_date'],
            'tdcurrentcreate' : tddata[0]['created_at'],
            'tdcurrentupdate' : tddata[0]['updated_at'],
        }


        print("추출된 해당 데이터:" , todocurrentdata)

        return JsonResponse(todocurrentdata)

        
        


  








# 1. 할일 생성

# todo/create

def todocreate(request):

    if request.method == 'POST':

        print("post_success_create")

        # 프론트에서 todo data 받아서 변수에 저장

        TodoPayload = json.loads(request.body)
        print("payload" , TodoPayload)

        tduserid = TodoPayload['userids']
        tdstatus = TodoPayload["tdstatus"]
        tdtitle = TodoPayload["tdtitle"]
        tdcontent = TodoPayload["tdcontent"]
        tdduedate = TodoPayload["tdduedate"]


        print("todo data: " , tduserid, tdstatus , tdtitle , tdcontent, tdduedate )


        # todo data저장

        new_todo = TodoModel.objects.create(user_id = tduserid ,status = tdstatus , title =tdtitle , content = tdcontent, due_date=tdduedate )

        print("새로운 todo저장되었습니다.")

        successdata = {
            'result' : True
        }

        return JsonResponse(successdata)
        


# 2. 할일 삭제

# todo/delete

def tododelete(request):

    if request.method == 'POST':

        # 삭제할 todo pk id받기
        TodoDeletePayload = json.loads(request.body)
        TodoPkId = TodoDeletePayload['todopkid']
        
        print('id:', TodoPkId)

        # 행 삭제하기

        deletetodo = TodoModel.objects.filter(id = TodoPkId)

        print("삭제될 행 추출" , deletetodo)

        GoDeleteToDo = deletetodo.delete()

        print("post_success_delete")

        data = {
            'success' : True
        }
        return JsonResponse(data)


# 3. 할일 수정

# todo/modify


def todomodify(request):

    if request.method == 'PUT':

        print("post_success_modify")

        modifyPayload = json.loads(request.body)

        print("modifypayload : ", modifyPayload)

        #  front에서 수정된 값을 비교하고 바뀌었을 경우 바뀐 값 저장 ,
        #  수정된 값이 null일 경우 -> 원래의 값으로 저장

        # 1. 해당 id에 맞는 현재 값 들
        currentToDo = TodoModel.objects.filter(id = modifyPayload['tdmdid']).values()

        # 2. 각 컬럼 (4가지 - status , title , content , due_date ) 비교

        newstatus = modifyPayload['tdmdstatus']
        newtitle = modifyPayload['tdmdtitle']
        newcontent = ''
        newduedate = ''

        # 2 - * 수정하기 버튼 클릭 시 그 시점으로 업데이트 처리하여 수정된 날짜 나오게 하기 위한 것
        newupdate= datetime.now()  

        # 2-1 -> status 비교             -> 수정 ok
        if modifyPayload['tdmdstatus'] == '':
            newstatus = currentToDo[0]['status'] 
            print("status is same")

        else : 
            print( "status is modify")
      
 
        # 2-2 -> title 비교      -> 수정  ok
        if modifyPayload['tdmdtitle'] == '':
            newtitle = currentToDo[0]['title']
            print("title is same")
          
        else : 
            print( "title is modify")


        # 2-3 -> content 비교   -> 수정 ok
        if modifyPayload['tdmdcontent'] :
            newcontent = modifyPayload['tdmdcontent']
           
        else :
            newcontent = currentToDo[0]['content']
            print("content is same")
         
        # 2-4 -> due date 비교   -> 수정 ok
        if modifyPayload['tdmdduedate'] == '':
            newduedate = currentToDo[0]['due_date']
            print("duedate is same")
        else :

            newduedate = modifyPayload['tdmdduedate']


        # 새로운 값으로 대체

        print("--------------------------------------------------------------------")

        print('새로운 값: ' , newstatus, newtitle,newcontent,newduedate )

        modify_todo= TodoModel.objects.filter(id = modifyPayload['tdmdid']).update(status =newstatus  , title =newtitle , content =newcontent , due_date=newduedate , updated_at = newupdate)

        print("변경완료되었습니다 -> " , modify_todo)


        data = {
            'resultmodify' : 0
        }

        return JsonResponse(data)

# 4. 상태 수정

# todo/statusmodify

def statusmodify(request):

    if request.method == "PUT":

        statusmodifyPayload = json.loads(request.body)

        statusmodifycurrent = TodoModel.objects.filter(id = statusmodifyPayload['statusid']).values('status')

        print("status 추출" ,statusmodifycurrent)


        # 클릭시 반대로 바꿔서 상태저장하기

        currentstatus = statusmodifycurrent[0]

        print("현상태값" ,currentstatus)

        newstatusTrue = True
        newstatusFalse = False

        data = {
            "result" : 1
        }

        
        # status 현재 상태 체크 후 반대상태로 업데이트 한 후 프론트로 응답하기
        
        if statusmodifycurrent[0]['status'] == False:
            updatestatus = TodoModel.objects.filter(id = statusmodifyPayload['statusid']).update(status = newstatusTrue)
            print("완료상태로 변경완료")
            return JsonResponse(data)
        
        else :
            print("not")

 
            

        if statusmodifycurrent[0]['status'] == True:
            updatestatus = TodoModel.objects.filter(id = statusmodifyPayload['statusid']).update(status = newstatusFalse)
            print("미완료 상태로 변경완료")
            return JsonResponse(data)
        else :
            print("not")
            
  • 1. POST - todo/sendtodo

    • 전체 list중 'status'가 'false'인 list를 보내주는 역할

      • 추가적으로, duedate 버튼에 따라 해당 list의 정렬상태를 관리
# todo/sendtodo   -> plan에 대한        
def sendtododb(request):

    if request.method == 'POST':

        useridPayload  = json.loads(request.body)
        ThisUserId = useridPayload['UserIdtd']
        print("get_success_sendtododata")


        #due_date정렬을 여기서 관리를 해줘야할거같다.
        #button - on -> order_by().reverse() 사용
        #button - off -> order_by() 만 사용

        button = useridPayload['duedatebtn']
        print("duedate" , button)

        # 정렬에 -> order_by() , reverse() 사용 
        if button == 0:
            TodoDBing = list(TodoModel.objects.order_by('due_date').filter(user_id=ThisUserId, status = False).values_list('id','status','title','content','due_date' ))
      
        
        else :
            TodoDBing = list(TodoModel.objects.order_by('due_date').reverse().filter(user_id=ThisUserId, status = False).values_list('id','status','title','content','due_date' ))
       


        print("현재 진행중: ", TodoDBing)
    
        data = {
            'tdmaining' : TodoDBing,
        }

        return JsonResponse(data)
  • session에 저장되어있는 , 즉 로그인되어있는 해당 user에 대한 todolist 값을 프론트에게 줘야하기 때문에,
    1. 프론트에서 userid를 받아오고,
    2. 위 userid와 일치하는 tdlist만 넘겨준다.
      
  • duedate버튼 - 화면에 보여지는 list의 정렬상태 관리
    • 기본값은 duedate가 오름차순으로 되게끔 ,list를 보여준다.
    • 하지만, duedatebtn을 클릭하였을때는, 반대로 내림차순이 되게끔 list를 보여준다.
    • 여기서 한번더 클릭시 , 원래대로 오름차순으로 된 list를 보여준다. 즉 , front에서 btn클릭에 대한 변수를 관리한뒤 그에 맞게 던져지는 값으로 오름차순인지 내림차순인지 결정되어 화면에 보여지는 것이다.

orm

TodoDBing = list(TodoModel.objects.order_by('due_date').filter(user_id=ThisUserId, status = False).values_list('id','status','title','content','due_date' ))
  • list() - 프론트에서 ngFor사용하여 화면에 보여줄거라, list형태로 가공
  • order_by('due_date') - default 는 지정해준 컬럼에 대한 오름차순 (기본값은 duedate에 따른 오름차순 정렬이기에 order_by사용)
  • filter(user_id =ThisUserId , status= False )
    • 로그인 된 사용자에 맞는 값, 그 중에서도 위 api에 맞게 status가 false인 값만 추출되도록
  • values_list() - 필요한 컬럼만 추출
  • 1. POST - todo/sendtodopopup

    • main 페이지에서 modify버튼을 클릭시, updatemode_popup창이 실행된다. 이때 해당 tdlist에 맞는 status,title,content와 같은 필요한 값들을 보내주는 역할을 한다.

# todo/sendtodopopup
# todopopup - 해당 id 값에 맞는 값들 전송

def sendtodopopup(request):

    if request.method == 'POST':

        print("get_success_sendpopup")

        # front에서 보낸 todo id 값 
        popupidPayload = json.loads(request.body)
        tdid = popupidPayload['tdpopupid']
        print("front에서 넘겨준 tododid: " , tdid)

        # todoDB 에서 usetdid와 동일한 값의 행 추출

        tddata = TodoModel.objects.filter(id = tdid).values()
        

        # front에 넘겨줄 data

        todocurrentdata = {
            'tdcurrentstatus' : tddata[0]['status'] ,
            'tdcurrenttitle' : tddata[0]['title'],
            'tdcurrentcontent' : tddata[0]['content'],
            'tdcurrentduedate' : tddata[0]['due_date'],
            'tdcurrentcreate' : tddata[0]['created_at'],
            'tdcurrentupdate' : tddata[0]['updated_at'],
        }


        print("추출된 해당 데이터:" , todocurrentdata)

        return JsonResponse(todocurrentdata)

  • 프론트에서 받아온 값에서 해당 list의 고유 todo_id를 추출한다.
  • todo db에서 해당 id에 맞는 열 필드 값 전체를 추출한다
      
  • 1. POST - todo/create

    • 새로운 todolist를 사용자가 작성하면 그 값들을 받아와 todo_db에 insert시켜주는 역할을 한다.
      
# 1. 할일 생성

# todo/create

def todocreate(request):

    if request.method == 'POST':

        print("post_success_create")

        # 프론트에서 todo data 받아서 변수에 저장

        TodoPayload = json.loads(request.body)
        print("payload" , TodoPayload)

        tduserid = TodoPayload['userids']
        tdstatus = TodoPayload["tdstatus"]
        tdtitle = TodoPayload["tdtitle"]
        tdcontent = TodoPayload["tdcontent"]
        tdduedate = TodoPayload["tdduedate"]


        print("todo data: " , tduserid, tdstatus , tdtitle , tdcontent, tdduedate )


        # todo data저장

        new_todo = TodoModel.objects.create(user_id = tduserid ,status = tdstatus , title =tdtitle , content = tdcontent, due_date=tdduedate )

        print("새로운 todo저장되었습니다.")

        successdata = {
            'result' : True
        }

        return JsonResponse(suc

orm

new_todo = TodoModel.objects.create(user_id = tduserid ,status = tdstatus , title =tdtitle , content = tdcontent, due_date=tdduedate )
  • create() - 새로운 data를 db에 생성하고 삽입한다.
  • 1. POST - todo/delete

    • 사용자가 삭제하고자 하는 list의 삭제 버튼을 클릭하였을때, 해당 list를 tododb에서 삭제시키는 역할을 한다.

# 2. 할일 삭제

# todo/delete

def tododelete(request):

    if request.method == 'POST':

        # 삭제할 todo pk id받기
        TodoDeletePayload = json.loads(request.body)
        TodoPkId = TodoDeletePayload['todopkid']
        
        print('id:', TodoPkId)

        # 행 삭제하기

        deletetodo = TodoModel.objects.filter(id = TodoPkId)

        print("삭제될 행 추출" , deletetodo)

        GoDeleteToDo = deletetodo.delete()

        print("post_success_delete")

        data = {
            'success' : True
        }
        return JsonResponse(data)
  • 삭제할 todolist의 고유 todo_id를 프론트에서 받아온다.
  • 해당 list 행을 tododb에서 추출한 후 delete()메소드를 사용하여 db에서 삭제한다.
      
  • 1. PUT - todo/modify

    • 사용자가 수정하고 싶은 list를 수정한 후 수정버튼을 누르면, 해당 list가 수정된 값으로 tododb에 업데이트 되서 저장되게 한다.
      
# 3. 할일 수정

# todo/modify


def todomodify(request):

    if request.method == 'PUT':

        print("post_success_modify")

        modifyPayload = json.loads(request.body)

        print("modifypayload : ", modifyPayload)

        #  front에서 수정된 값을 비교하고 바뀌었을 경우 바뀐 값 저장 ,
        #  수정된 값이 null일 경우 -> 원래의 값으로 저장

        # 1. 해당 id에 맞는 현재 값 들
        currentToDo = TodoModel.objects.filter(id = modifyPayload['tdmdid']).values()

        # 2. 각 컬럼 (4가지 - status , title , content , due_date ) 비교

        newstatus = modifyPayload['tdmdstatus']
        newtitle = modifyPayload['tdmdtitle']
        newcontent = ''
        newduedate = ''

        # 2 - * 수정하기 버튼 클릭 시 그 시점으로 업데이트 처리하여 수정된 날짜 나오게 하기 위한 것
        newupdate= datetime.now()  

        # 2-1 -> status 비교             -> 수정 ok
        if modifyPayload['tdmdstatus'] == '':
            newstatus = currentToDo[0]['status'] 
            print("status is modify")

        else : 
            print( "status is modify")
      
 
        # 2-2 -> title 비교      -> 수정  ok
        if modifyPayload['tdmdtitle'] == '':
            newtitle = currentToDo[0]['title']
            print("title is same")
          
        else : 
            print( "title is modify")


        # 2-3 -> content 비교   -> 수정 ok , 
        # 값이 있으면  if x :
        if modifyPayload['tdmdcontent'] :
            newcontent = modifyPayload['tdmdcontent']
            print('컨텐트 ',modifyPayload['tdmdcontent'] )
           
        else :
            newcontent = currentToDo[0]['content']
            print("content is same")
         
        # 2-4 -> due date 비교   -> 수정 ok
        if modifyPayload['tdmdduedate'] == '':
            newduedate = currentToDo[0]['due_date']
            print("duedate is same")
        else :

            newduedate = modifyPayload['tdmdduedate']


        # 새로운 값으로 대체

        print("--------------------------------------------------------------------")

        print('새로운 값: ' , newstatus, newtitle,newcontent,newduedate )

        modify_todo= TodoModel.objects.filter(id = modifyPayload['tdmdid']).update(status =newstatus  , title =newtitle , content =newcontent , due_date=newduedate , updated_at = newupdate)

        print("변경완료되었습니다 -> " , modify_todo)


        data = {
            'resultmodify' : 0
        }

        return JsonResponse(data)
  • 사용자가 어느 한 필드만 수정하고 싶을 수도 있기에, 어떤 필드들은 null값으로 프론트에서 값이 전달 될 수 있다고 생각하였다.
  • 수정될 각 필드에 대해 프론트에서 받아온 값이 null값인지 아닌지에 따라 새롭게 업데이트 될 변수의 저장되는 값이 달라지게끔 했다.
    • null(x) -> 새로 입력된 값이 변수에 저장
    • null(o) -> 기존의 값으로 변수에 저장
  • 각 필드별로 null체크를 해준뒤 새로운 업데이트 변수에 저장이 끝나면 update()함수를 사용하여 tododb에 업데이트 시킨다.
      
  • 1. PUT - todo/statusmodify

    • main 화면에서 status가 false인 현재진행중인 섹션과 status가 true인 완료 섹션의 list들 중에서 사용자가 status버튼을 클릭하여 상태값을 바꿀떄 status값이 바뀐상태로 tododb에 저장되게 한다
      
# 4. 상태 수정

# todo/statusmodify

def statusmodify(request):

    if request.method == "PUT":

        statusmodifyPayload = json.loads(request.body)

        statusmodifycurrent = TodoModel.objects.filter(id = statusmodifyPayload['statusid']).values('status')

        print("status 추출" ,statusmodifycurrent)


        # 클릭시 반대로 바꿔서 상태저장하기

        currentstatus = statusmodifycurrent[0]

        print("현상태값" ,currentstatus)

        newstatusTrue = True
        newstatusFalse = False

        data = {
            "result" : 1
        }

        
        # status 현재 상태 체크 후 반대상태로 업데이트 한 후 프론트로 응답하기
        
        if statusmodifycurrent[0]['status'] == False:
            updatestatus = TodoModel.objects.filter(id = statusmodifyPayload['statusid']).update(status = newstatusTrue)
            print("완료상태로 변경완료")
            return JsonResponse(data)
        
        else :
            print("not")

 
            

        if statusmodifycurrent[0]['status'] == True:
            updatestatus = TodoModel.objects.filter(id = statusmodifyPayload['statusid']).update(status = newstatusFalse)
            print("미완료 상태로 변경완료")
            return JsonResponse(data)
        else :
            print("not")
  • 프론트에서는 status버튼이 클릭된 list의 해당 id만 받아온다.
  • 받아온 todo id를 사용하여 해당 list의 현재 status상태를 추출한다.
  • 추출된 상태가 false 이면 true로 수정된채로 tododb에 업데이트되게 , true이며 false로 수정된채로 db에 업데이트 되게 한다.

profile
밑거름이라고생각합니다

0개의 댓글