service: aws-python-pynamodb-s3-sigurl

frameworkVersion: ">=1.1.0 <2.0.0"

plugins:
  - serverless-python-requirements

package:
  exclude:
    - node_modules/**
    - .idea/**
    - .requirements/**
    - env/**
    - README.md
    - package.json
    - package-lock.json
    - requirements.txt

# DRY constants: define all compound/generated names in one place
# Override args are: .. defaults:
# --app_acroym          signed-uploader
# --s3_bucket           self:custom.app_acronym
# --s3_key_base         self:custom.stage
# --region              us-east-1
# --stage               test
# --deletion_policy     delete
custom:
  app_acronym: sig-s3-uploader
  default_stage: test
  stage: ${opt:stage, self:custom.default_stage}
  stack_name: ${self:custom.app_acronym}-${self:custom.stage}
  region: ${opt:region, self:provider.region}
  deletion_policy: Delete
  dynamodb_table: ${self:custom.stack_name}
  dynamodb_arn: arn:aws:dynamodb:${self:custom.region}:*:table/${self:custom.dynamodb_table}
  dynamodb_host: https://dynamodb.${self:custom.region}.amazonaws.com
  # Default to using app_acronym as bucket name
  s3_bucket: ${opt:s3_bucket, self:custom.app_acronym}
  # default to using ${stage} as key base path, keeps stages from namespace collisions
  s3_key_base: ${opt:s3_key_base, self:custom.stage}
  s3_bucket_arn: arn:aws:s3:::${self:custom.s3_bucket}
  s3_role_resource: ${self:custom.s3_bucket_arn}/${self:custom.s3_key_base}/*
  # Put this here rather than in code (presigned URL TTL)
  url_default_ttl: 60

provider:
  name: aws
  runtime: python3.6
  region: us-east-1
  environment:
    DYNAMODB_TABLE: ${self:custom.dynamodb_table}
    DYNAMODB_HOST: ${self:custom.dynamodb_host}
    REGION: ${self:custom.region}
    S3_BUCKET: ${self:custom.s3_bucket}
    S3_KEY_BASE: ${self:custom.s3_key_base}
    URL_DEFAULT_TTL: ${self:custom.url_default_ttl}
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
        - dynamodb:DescribeTable
      Resource: ${self:custom.dynamodb_arn}

    - Effect: Allow
      Action:
        - s3:*
      Resource: ${self:custom.s3_role_resource}

functions:
  create:
    name: ${self:custom.stack_name}-create
    description: Generate a presigned URL for PUT upload
    handler: asset/create.create
    events:
      - http:
          path: asset
          method: post
          cors: true
          integration: lambda

  bucket:
    handler: asset/bucket.event
    name: ${self:custom.stack_name}-bucket
    description: Called by s3 create/remove events to manage asset state in dynamo
    events:
      - s3:
          bucket: ${self:custom.s3_bucket}
          event: s3:ObjectCreated:*
          rules:
            - prefix: ${self:custom.s3_key_base}
      - s3:
          bucket: ${self:custom.s3_bucket}
          event: s3:ObjectRemoved:*
          rules:
            - prefix: ${self:custom.s3_key_base}

  list:
    handler: asset/list.asset_list
    name: ${self:custom.stack_name}-list
    description: List all assets
    events:
      - http:
          path: asset
          method: get
          cors: true
          integration: lambda

  get:
    handler: asset/get.get
    name: ${self:custom.stack_name}-get
    description: Get a presigned download url for <asset-id>
    events:
      - http:
          path: asset/{asset_id}
          method: get
          cors: true
          integration: lambda
          request:
            paths:
              asset_id: true
              parameters:
                 paths:
                   timeout: true
  update:
    handler: asset/update.update
    name: ${self:custom.stack_name}-update
    description: Mark an RECEIVED asset as UPLOADED, fail if not RECEIVED
    events:
      - http:
          path: asset/{asset_id}
          method: put
          cors: true
          integration: lambda
          request:
            paths:
              asset_id: true
  delete:
    handler: asset/delete.delete
    name: ${self:custom.stack_name}-delete
    description: Delete an asset by <asset-id>
    events:
      - http:
          path: asset/{asset_id}
          method: delete
          cors: true
          integration: lambda
          request:
            paths:
              asset_id: true

resources:
  Resources:

# Comment assetDynamoDbTable if using existing table
    assetDynamoDbTable:
      Type: 'AWS::DynamoDB::Table'
      DeletionPolicy: ${self:custom.deletion_policy}
      Properties:
        AttributeDefinitions:
          -
            AttributeName: asset_id
            AttributeType: S
        KeySchema:
          -
            AttributeName: asset_id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: ${self:custom.dynamodb_table}
