inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[인프런 워밍업 스터디 클럽 3기 풀스택] 2주차 발자국

치현
1



학습 내용

인프런 워밍업 클럽 스터디 2주차로,

이번 주는 드롭 박스 프로젝트와 함께 Supabase의 Storage를 다뤄볼 수 있는 시간이었다.

 

Supbase Storage

1. 기본 구성 요소

2. 접근 제어 모델

3. 보안 기능

4. 이미지 변환 기능 (Pro Plan 이상)

5. 인증 방식

6. 통합 기능

7. 제한사항



미션 2 구현 내용

과제 구현 저장소

image

Dropbox 중

파일의 마지막 수정(업로드) 시간을 표시하는 기능 추가 하기

 

export interface FileObject {
  name: string
  bucket_id: string
  owner: string
  id: string
  updated_at: string
  created_at: string
  last_accessed_at: string
  metadata: Record<string, any>
  buckets: Bucket
}

=> DropboxImage 컴포넌트가 prop으로 받는 image의 타입은 FileObject로 그 중 업로드시간created_at을 의미하기에 이를 이미지에 추가하였다.(사진 참고)

 

포인트 1: 한글 파일명 es-hangul 사용

// 안전한 파일명 생성을 위한 유틸리티
export class FileNameConverter {
  // 안전한 문자 패턴 정의
  private static readonly SAFE_CHARACTERS = /^[a-zA-Z0-9!\-_.*'()]+$/;

  private static generateRandomString(length: number = 8): string {
    const chars =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    return Array.from({ length }, () =>
      chars.charAt(Math.floor(Math.random() * chars.length))
    ).join("");
  }

  // 파일명이 안전한 문자들로만 구성되었는지 확인
  private static isSafeFileName(name: string): boolean {
    return this.SAFE_CHARACTERS.test(name);
  }

  // 안전하지 않은 문자를 포함한 파일명을 안전한 형식으로 변환
  private static convertToSafeFileName(name: string): string {
    try {
      // 파일명 정규화
      const normalized = name.trim().normalize();

      // 한글이나 특수문자가 있는지 확인
      const hasKorean = /[ㄱ-ㅎㅏ-ㅣ가-힣]/.test(normalized);
      const hasSpecialChars = /[^A-Za-z0-9]/.test(normalized);

      if (!hasKorean && !hasSpecialChars) {
        return normalized;
      }

      // 한글이 있는 경우 로마자로 변환 시도
      if (hasKorean) {
        const romanized = romanize(normalized);
        if (romanized && romanized !== normalized) {
          // 로마자 변환 결과에서 안전하지 않은 문자 제거
          return romanized.replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
        }
      }

      // 변환 실패 시 랜덤 문자열 생성
      return this.generateRandomString();
    } catch (error) {
      console.error("Conversion error:", error);
      return this.generateRandomString();
    }
  }

  // 원본 파일명을 안전한 형식으로 변환
  static encode(fileName: string): string {
    console.log("Original filename:", fileName);

    const extension = fileName.split(".").pop() || "";
    const nameWithoutExt = fileName.slice(0, fileName.lastIndexOf("."));

    const safeName = this.isSafeFileName(nameWithoutExt)
      ? nameWithoutExt
      : this.convertToSafeFileName(nameWithoutExt);

    console.log("Safe filename:", safeName);

    return `${safeName}_${Date.now()}.${extension}`;
  }

  // 파일명에서 타임스탬프 제거하여 원본 이름 추출
  static decode(fileName: string): string {
    const [name] = fileName.split("_");
    return name || fileName;
  }
}

포인트 2 : 업로드 날짜 표시

export function formatDate(timestamp: string): string {
  const date = new Date(timestamp);
  const now = new Date();
  const diff = now.getTime() - date.getTime();

  // 1일 이내
  if (diff < 24 * 60 * 60 * 1000) {
    const hours = Math.floor(diff / (60 * 60 * 1000));
    if (hours < 1) {
      const minutes = Math.floor(diff / (60 * 1000));
      return `${minutes}분 전`;
    }
    return `${hours}시간 전`;
  }

  // 30일 이내
  if (diff < 30 * 24 * 60 * 60 * 1000) {
    const days = Math.floor(diff / (24 * 60 * 60 * 1000));
    return `${days}일 전`;
  }

  // 그 외
  return date.toLocaleDateString("ko-KR", {
    year: "numeric",
    month: "long",
    day: "numeric",
  });
}


회고

파일명 변환하는데 생각보다 시간이 많이 소요됐다.

여찌저찌 구현은 헀지만, 이미지가 어떻게 encoding되고 decoding되는지 일련의 과정에 대한 공부가 필요함을 느끼는 이번주 였다.

 

 

풀스택 풀스택 인프런워밍업스터디클럽 Next 3기 Supabase React 프론트엔드 2주차 발자국

답변 1

0

leeebug

저도 한글파일명 변환하는 부분에서 애먹었네요..ㅎㅎ
es-hangle 찾아봐야겠네요. 감사합니다!
이번주도 고생하셨습니다..!