برنامه نویسی

سری Amplify، قسمت 5: آپلود و بازیابی تصاویر با Amplify Storage

با وجود برنامه ما، اکنون زمان آن فرا رسیده است که با استفاده از برخی دیگر از دسته بندی های Amplify، قابلیت های بیشتری را اضافه کنیم. در این مقاله اضافه خواهیم کرد Amplify Storage برای آپلود و بازیابی تصاویر از AWS تنها در چند مرحله.

ما با اضافه کردن شروع خواهیم کرد Amplify Storage دسته بندی پروژه ما ما با استفاده از مولفه Storage پیگیری خواهیم کرد تا بتوانیم همه تصاویر خود را آپلود و فهرست کنیم. در نهایت، ما یک UI ایجاد می کنیم که از این قابلیت استفاده می کند. در پایان این مقاله، درک بهتری از آن خواهید داشت Amplify Storage و می تواند از آن در هر سناریویی در مورد آپلود و بازیابی فایل استفاده کند.

افزودن Amplify Storage به پروژه ما

ما در مخزن جایی که در آخرین پست وبلاگ متوقف کردیم ادامه خواهیم داد. از این نقطه ما اجرا خواهیم کرد تقویت حافظه افزودن با گزینه های زیر:

  • سرویس: محتوا.
  • اسم دوستانه: تقویت تصاویر.
  • نام سطل: تقویت تصاویر
  • دسترسی: ایجاد، به روز رسانی، خواندن، و حذف، فقط برای کاربران مجاز.

خروجی Amplify CLI شبیه این خواهد بود:

Evertsons-MBP:theamplifyapp evertsoncroes$ amplify add storage

? Select from one of the below mentioned services: Content (Images, audio, video, etc.)

✔ Provide a friendly name for your resource that will be used to label this category in the project: · amplifyappimages

✔ Provide bucket name: · amplifyappimages

✔ Who should have access: · Auth users only

✔ What kind of access do you want for Authenticated users? · create/update, read, delete

✔ Do you want to add a Lambda Trigger for your S3 Bucket? (y/N) · no

✅ Successfully added resource amplifyappimages locally

⚠️ If a user is part of a user pool group, run "amplify update storage" to enable IAM group policies for CRUD operations
✅ Some next steps:
"amplify push" builds all of your local backend resources and provisions them in the cloud

"amplify publish" builds all of your local backend and front-end resources (if you added hosting category) and provisions them in the cloud
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما می خواهیم کاربران بتوانند فقط آپلودهای خودشان را ببینند. بنابراین مهم است که انتخاب کنیم فقط کاربران تأیید شده بتوانند از این منبع استفاده کنند و همه مجوزها را به آنها بدهیم تا بتوانند تصاویر را آپلود، مشاهده و حذف کنند. این یک مثال مفید دیگر از چگونگی Amplify Auth دسته به طور خودکار با سایر دسته ها پیوند می یابد تا قابلیت احراز هویت و مجوز را ارائه دهد.

این دستور تغییراتی را به مخزن ما اضافه می کند. در مرحله بعد شروع به استفاده از دسته جدید خواهیم کرد.

ما این قابلیت را به سه جزء تقسیم می کنیم:

  • آپلود کننده تصویر: جزء مسئول آپلود تصویر و دادن بازخورد کاربر در مورد آپلود.
  • آلبوم تصویر: مؤلفه ای که مسئول فهرست کردن همه تصاویر آپلود شده است.
  • نمایشگر تصویر: کامپوننتی که فقط یک تصویر را به صورت مدال نشان می دهد.

افزودن یک صفحه نمای کلی تصویر

ابتدا با افزودن یک کامپوننت Angular جدید که برای نمایش تمام تصاویری که کاربران آپلود کرده‌اند استفاده می‌کنیم:

ng generate component components/categories/storage
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این فایل های مورد انتظار را برای کامپوننت ما ایجاد می کند. سپس مسیریابی را پیوند خواهیم داد تا بتوانیم این مؤلفه را ارائه دهیم. اینها همه چیزهای استاندارد Angular است که در وبلاگ قبلی انجام داده ایم، لطفاً برای جزئیات به این commit مراجعه کنید.

افزودن قابلیت آپلود تصویر

اکنون کامپوننتی را اضافه می کنیم که حاوی قابلیت آپلود یک تصویر است:

ng generate component components/categories/storage/image-upload
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با این کار فایل های Angular مورد انتظار تولید می شود. داخل ما storage.component.html ما مطمئن می شویم که آپلود تصویر جدید ایجاد شده را اضافه می کنیم:

<app-image-upload></app-image-upload>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

درون image-upload.component.html، اضافه می کنیم:

<input
  type="file"
  id="imageUpload"
  name="imageUpload"
  accept="image/png, image/jpeg"
  (change)="imageSelected($event)"
/>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این یک ورودی به ما می دهد که می توانیم از آن برای انتخاب تصاویر از دستگاه خود استفاده کنیم. ما باید منطقی را اضافه کنیم تا هر زمان که کاربر تصویری را در ما انتخاب می کند به آن واکنش نشان دهیم image-upload.component.ts:

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

@Component({
  selector: 'app-image-upload',
  templateUrl: './image-upload.component.html',
  styleUrls: ['./image-upload.component.css']
})
export class ImageUploadComponent implements OnInit {
  selectedFile: File | undefined = undefined;

  constructor() {}

  ngOnInit(): void {}

  imageSelected = (e: Event) => {
    const input = e.target as HTMLInputElement;

    if (!input.files?.length) {
      return;
    }

    this.selectedFile = input.files[0];
  };
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با این تغییر متغیر SelectFile را طوری تنظیم می کنیم که حاوی محتویات فایلی باشد که انتخاب کرده ایم. اکنون که این مورد را داریم، می‌توانیم یک دکمه آپلود اضافه کنیم که تصویر انتخاب شده را در ابر AWS آپلود می‌کند، که قبلاً آن را پیکربندی کرده بودیم.

ما با اضافه کردن یک دکمه شروع خواهیم کرد image-upload.component.html:

<input
  type="file"
  id="imageUpload"
  name="imageUpload"
  accept="image/png, image/jpeg"
  (change)="imageSelected($event)"
/>

<button class="aws-button" (click)="uploadImage()"> <!---NEW!-->
  Upload
</button>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از کلیک بر روی این دکمه، تابع uploadImage فراخوانی می شود. این تابع را به شکل زیر در ما تعریف می کنیم image-upload.component.ts:

import { Component, OnInit } from '@angular/core';
import { Storage } from 'aws-amplify'; // <--- add this

@Component({
  selector: 'app-image-upload',
  templateUrl: './image-upload.component.html',
  styleUrls: ['./image-upload.component.css']
})
export class ImageUploadComponent implements OnInit {
  selectedFile: File | undefined = undefined;

  constructor() {}

  ngOnInit(): void {}

  //Add this function!
  uploadImage = async () => {
    if (!this.selectedFile) {
      return;
    }
    try {
      await Storage.put(this.selectedFile.name, this.selectedFile, {
        contentType: 'image/*',
        level: 'private'
      });
    } catch (error) {
      console.log('Error uploading file: ', error);
    }
  };

  //other code
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ابتدا جزء Storage را از آن وارد می کنیم aws-amplify. سپس ما را تعریف می کنیم uploadImage عملکردی که توسط دکمه جدید ما استفاده می شود. این تابع از مولفه Amplify Storage استفاده می کند و متد put را فراخوانی می کند که نام فایل، محتویات فایل و برخی ویژگی ها را دریافت می کند.

در این حالت گزینه ها شامل نوع فایل مورد نظر ما و سطح مجوز می باشد. تنظیم سطح به private یعنی تنها کاربری که این تصویر را آپلود کرده است به آن دسترسی خواهد داشت.

هنگامی که ما این را در جای خود قرار دادیم، می‌توانیم یک تصویر را با ورودی خود انتخاب کرده و با استفاده از دکمه جدید آن را آپلود کنیم. در حالی که ما هنوز هیچ بازخوردی نمی بینیم، اگر به کنسول AWS خود در S3 برویم و سطل خود را جستجو کنیم، باید ببینیم که یک دایرکتوری جدید به نام “private” وجود دارد که حاوی دایرکتوری با شناسه شناسه کاربر مورد استفاده ما است. برای آپلود تصویر در داخل این دایرکتوری می توانیم تصویری را که آپلود شده است مشاهده کنیم:

توضیحات تصویر

افزودن بازخورد پیشرفت آپلود فایل

در این مرحله می خواهیم به کاربر بازخوردی در مورد فرآیند آپلود تصویر نشان دهیم. ما با اضافه کردن یک enum برای وضعیت‌های آپلود احتمالی شروع می‌کنیم و متغیری را در مؤلفه خود تنظیم می‌کنیم تا وضعیت صحیح را با توجه به وضعیت فرآیند آپلود داشته باشد. در رابط کاربری خود، متنی را بر اساس این حالت نشان خواهیم داد.

ما ابتدا این تغییرات را در خود ایجاد می کنیم image-upload.component.ts:

import { Component, OnInit } from '@angular/core';
import { Storage } from 'aws-amplify';

//Add this!
enum UploadState {
  IDLE,
  UPLOADING,
  UPLOAD_COMPLETE,
  ERROR
}

@Component({
  selector: 'app-image-upload',
  templateUrl: './image-upload.component.html',
  styleUrls: ['./image-upload.component.css']
})
export class ImageUploadComponent implements OnInit {
  selectedFile: File | undefined = undefined;
  //Add these 3:
  uploadStates = UploadState;
  uploadState: UploadState = UploadState.IDLE;
  progressText: string = '';

  constructor() {}

  ngOnInit(): void {}

  uploadImage = async () => {
    this.uploadState = UploadState.UPLOADING; // <--- Add this
    if (!this.selectedFile) {
      return;
    }
    try {
      await Storage.put(this.selectedFile.name, this.selectedFile, {
        contentType: 'image/*',
        level: 'private',
        progressCallback: this.progressCallback // <---- Add this
      });
      this.uploadState = UploadState.UPLOAD_COMPLETE; // <--- Add this
    } catch (error) {
      this.uploadState = UploadState.ERROR; // <---- Add this
      console.log('Error uploading file: ', error);
    }
  };

  //Add this function!
  progressCallback = (progress: any) => {
    this.progressText = `Uploaded: ${(progress.loaded / progress.total) *
      100} %`;
  };

  imageSelected = (e: Event) => {
    this.uploadState = UploadState.IDLE; // <---- Add this
    const input = e.target as HTMLInputElement;

    if (!input.files?.length) {
      return;
    }

    this.selectedFile = input.files[0];
  };
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

وضعیت آپلود در شروع خواهد شد IDLE، تغییر به UPLOADING و یا وارد خواهد شد UPLOADING_COMPLETE یا ERROR بسته به نحوه انجام تماس به Amplify Storage. تابع Storage.put همچنین امکان تعریف a را فراهم می کند progressCallback عملکرد به منظور پیگیری پیشرفت آپلود.

پس از تنظیم این موارد، موارد زیر را به موارد زیر اضافه می کنیم image-upload.component.html برای اینکه بتوانید بازخورد را ببینید:

<!---Existing code-->

<p
  *ngIf="
    uploadState === uploadStates.UPLOADING ||
    uploadState === uploadStates.UPLOAD_COMPLETE
  "
>
  {{ progressText }}
</p>
<p *ngIf="uploadState === uploadStates.UPLOAD_COMPLETE">
  Upload complete!
</p>

<p class="error-text" *ngIf="uploadState === uploadStates.ERROR">
  Something went wrong with the file upload
</p>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون هنگام آپلود تصاویر، بازخوردهایی دریافت خواهیم کرد.

مجموعه کامل تغییرات این مرحله را می توانید در این commit پیدا کنید.

افزودن نمای کلی تصویر

اکنون که می‌توانیم تصاویر را آپلود کنیم، می‌خواهیم تمام تصاویر آپلود شده خود را مشاهده کنیم. ما با ایجاد یک جزء تصویر-آلبوم شروع می کنیم:

ng generate component components/categories/storage/image-album
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون می خواهیم به روز رسانی کنیم image-album.component.ts حاوی منطق برای دریافت همه تصاویر برای کاربر ما:

import { Component, OnInit } from '@angular/core';
import { Storage } from 'aws-amplify';

export interface Image {
  key: string;
  url: string;
}

@Component({
  selector: 'app-image-album',
  templateUrl: './image-album.component.html',
  styleUrls: ['./image-album.component.css']
})
export class ImageAlbumComponent implements OnInit {
  images: Image[] = [];

  constructor() {}

  ngOnInit(): void {
    this.getAllImages();
  }

  getAllImages = () => {
    Storage.list('', { level: 'private' })
      .then(result => {
        result.forEach(async imageObject => {
          const objectKey = imageObject.key;

          if (objectKey !== undefined) {
            const signedURL = await Storage.get(objectKey, {
              level: 'private',
              download: false
            });

            this.images.push({ key: objectKey, url: signedURL });
          }
        });
      })
      .catch(err => console.log(err));
  };
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برخی از موارد مهمی که در اینجا باید به آنها توجه کرد این است که سطوح را در هر دو حالت خصوصی تنظیم کنید Storage.list و Storage.get کارکرد. دلیل اینکه ما باید از دو تابع استفاده کنیم این است که Storage.list فقط اطلاعاتی در مورد اشیا به ما می دهد، مانند کلید یکتا در S3. با این حال از URL استفاده نمی کند که با آن بتوانیم در واقع شی را مشاهده کنیم.

برای این ما به یک URL امضا شده نیاز داریم. چون ما وارد شده ایم و با آن تماس می گیریم Storage.get عملکرد با private سطح، Amplify Storage مؤلفه بررسی می کند که کدام کاربر وارد شده است و تأیید می کند که این کاربر می تواند این شی را مشاهده کند و یک URL امضا شده ایجاد کند.

ما همچنین ایجاد کردیم Image رابطی که برای حاوی کلید تصویر و نشانی اینترنتی امضا شده بازیابی شده از آن استفاده خواهیم کرد S3. ما اینها را در یک آرایه روی کامپوننت ذخیره می کنیم و برای نمایش تصاویر در آنها حلقه می زنیم image-album.component.html:

<div class="container">
  <div class="row" *ngFor="let image of images">
    <div class="col-lg-2"></div>
    <div class="col-lg-8">
      <img class="album-image" src="{{ image.url }}" />
    </div>
    <div class="col-lg-2"></div>
  </div>
</div>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این به سادگی از طریق imageUrls حلقه می زند و یک تصویر برای هر یک نشان می دهد. ما همچنین یک ظاهر طراحی را اضافه می کنیم تا عرض و کمی حاشیه به ما اضافه شود image-album.component.css:

.album-image {
  width: 100%;
  margin: 8px;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این باعث می شود که تصاویر در صفحه به صورت زیر مشاهده شوند:

توضیحات تصویر

برای همه تغییرات کد، از جمله سیم کشی مولفه جدید، این commit را ببینید.

افزودن قابلیت حذف تصویر

در این بخش قصد داریم دکمه ای برای حذف تصاویری که آپلود کرده ایم اضافه کنیم. ابتدا a را اضافه می کنیم removeImage عملکرد در ما image-album.component.ts:

removeImage = async (key: string) => {
    await Storage.remove(key, { level: 'private' });
    this.images = [];
    this.getAllImages();
  };
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما آرایه تصاویر را در اینجا مجدداً اختصاص می دهیم تا Angular را مجبور کنیم که مولفه تصویر-آلبوم را دوباره رندر کند تا بتوانیم ببینیم که تصویر ما واقعاً حذف شده است. سپس ما خود را به روز می کنیم image-album.component.html برای حذف یک دکمه “x” در کنار هر تصویر:

<div class="container">
  <div class="row" *ngFor="let image of images">
    <div class="col-lg-2"></div>
    <div class="col-lg-8">
      <img class="album-image" src="{{ image.url }}" />
    </div>
    <div class="col-lg-2"> <!--NEW! -->
      <button class="remove-image-button" (click)="removeImage(image.key)">
        x
      </button>
    </div>
  </div>
</div>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و کمی استایل به دکمه اضافه می کنیم:

.remove-image-button {
  border: 0px;
  background: transparent;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و اکنون دکمه ای داریم که به ما امکان می دهد تصاویر را حذف کنیم که چیزی شبیه به این خواهد بود:

توضیحات تصویر

مثل همیشه، تغییرات این مرحله را می توانید در این commit پیدا کنید.

تنظیم حداکثر تعداد آپلود برای هر کاربر

آخرین مرحله ای که می خواهیم برای آپلود تصویر خود اضافه کنیم این است که حداکثر تعداد تصاویر را به ازای هر کاربر اضافه کنیم تا کاربر به ما سیل نکند. S3 سطل ها ما ملکی برای این کار نداریم Amplify Storage جزء، بنابراین ما باید این را خودمان بسازیم. همچنین، توجه داشته باشید که راه حل در اینجا فقط یک بررسی frontend است، هیچ بررسی واقعی روی خود سطل به ازای هر کاربر وجود ندارد.

ما تغییرات زیر را در خود ایجاد می کنیم image-upload.component.ts:

import { Component, OnInit } from '@angular/core';
import { Storage } from 'aws-amplify';

const MAX_NUMBER_OF_IMAGES_PER_USER: number = 10;

enum UploadState {
  IDLE,
  UPLOADING,
  UPLOAD_COMPLETE,
  ERROR,
  MAX_REACHED // <--- add this!
}

@Component({
  selector: 'app-image-upload',
  templateUrl: './image-upload.component.html',
  styleUrls: ['./image-upload.component.css']
})
export class ImageUploadComponent implements OnInit {
  //Existing code...

  uploadImage = async () => {
    this.uploadState = UploadState.UPLOADING;
    if (!this.selectedFile) {
      return;
    }
    try {
      //Add this part!
      const userImages = await Storage.list('', { level: 'private' });
      if (userImages.length >= MAX_NUMBER_OF_IMAGES_PER_USER) {
        this.uploadState = UploadState.MAX_REACHED;
        return;
      }

     //Existing code...
    } catch (error) {
      //Existing code ...
    }
  };

  //Existing code...
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ابتدا یک حالت جدید به نام اضافه می کنیم MAX_REACHED که در صورت وجود این مورد تنظیم خواهیم کرد. درون uploadImage تابع ما یک بررسی جدید اضافه می کنیم که در آن ابتدا اشیاء کاربر را لیست می کنیم و بررسی می کنیم که آیا طول برابر است یا بزرگتر از حداکثر. اگر اینطور باشد، وضعیت آپلود را روی آن تنظیم می کنیم MAX_REACHED و آپلود را متوقف کنید

در ما image-upload.component.html، یک پیام خطای جدید اضافه می کنیم که در این وضعیت آپلود نشان داده می شود:

<!---Existing code...-->

<p class="error-text" *ngIf="uploadState === uploadStates.MAX_REACHED">
  Reached maximum amount of uploads. Please remove an image before trying again.
</p>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا وقتی می‌خواهیم تصویر یازدهم را اضافه کنیم، پیام زیر را دریافت می‌کنیم:

توضیحات تصویر

تغییرات این مرحله را می توانید در اینجا پیدا کنید.

بعدی: هوش مصنوعی و ML با پیش‌بینی‌های تقویت‌کننده

در این وبلاگ از Amplify Storage دسته برای به روز رسانی برنامه موجود ما به منظور آپلود، مشاهده و حذف تصویر به ازای هر کاربر. در مقاله بعدی به استفاده از قدرت هوش مصنوعی و یادگیری ماشینی با آن خواهیم پرداخت Amplify Predictions.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا