From 74621e997cb96c302c7ff55f6a0fa514ebc38bc8 Mon Sep 17 00:00:00 2001 From: James Kachel Date: Wed, 17 Jan 2024 08:59:52 -0600 Subject: [PATCH 1/6] Pulled CI workflow into a runnable place, removed JS tests for now, minor updates for this codebase --- {.github-ex/workflows => .github}/ci.yml | 80 +++--------------------- 1 file changed, 9 insertions(+), 71 deletions(-) rename {.github-ex/workflows => .github}/ci.yml (61%) diff --git a/.github-ex/workflows/ci.yml b/.github/ci.yml similarity index 61% rename from .github-ex/workflows/ci.yml rename to .github/ci.yml index 4df54496..936d773c 100644 --- a/.github-ex/workflows/ci.yml +++ b/.github/ci.yml @@ -8,7 +8,7 @@ jobs: # Label used to access the service container db: # Docker Hub image - image: postgres:12.11 + image: postgres:16 # Set health checks to wait until postgres has started options: >- --health-cmd pg_isready @@ -27,19 +27,6 @@ jobs: ports: - 6379:6379 - elastic: - image: docker.elastic.co/elasticsearch/elasticsearch:7.10.0 - env: - network.host: "0.0.0.0" - http.cors.enabled: "true" - http.cors.allow-origin: "*" - http.max_content_length: "10mb" - rest.action.multi.allow_explicit_index: "false" - ES_JAVA_OPTS: "-Xms1024m -Xmx1024m" - discovery.type: "single-node" - ports: - - 9200:9200 - steps: - uses: actions/checkout@v3 @@ -58,7 +45,7 @@ jobs: - uses: actions/setup-python@v4 with: - python-version: "3.11.5" + python-version: "3.12.1" cache: "poetry" - name: Validate lockfile @@ -69,77 +56,28 @@ jobs: - name: Lint run: poetry run ruff --extend-ignore=D1 $(git ls-files '*.py') - - name: Create test local state - run: ./scripts/test/stub-data.sh + - name: Tests run: | export MEDIA_ROOT="$(mktemp -d)" ./scripts/test/python_tests.sh env: DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres # pragma: allowlist secret - MITOPEN_SECURE_SSL_REDIRECT: "False" - MITOPEN_DB_DISABLE_SSL: "True" - MITOPEN_FEATURES_DEFAULT: "True" - OPENSEARCH_URL: localhost:9200 CELERY_TASK_ALWAYS_EAGER: "True" CELERY_BROKER_URL: redis://localhost:6379/4 CELERY_RESULT_BACKEND: redis://localhost:6379/4 - TIKA_CLIENT_ONLY: "True" - MITOPEN_BASE_URL: http://localhost:8063/ - MAILGUN_KEY: fake_mailgun_key - MAILGUN_SENDER_DOMAIN: other.fake.site - OPENSEARCH_INDEX: testindex - INDEXING_API_USERNAME: mitodl - MITOPEN_COOKIE_DOMAIN: localhost - MITOPEN_COOKIE_NAME: cookie_monster + MITOL_UE_COOKIE_NAME: "mitolue" + MITOL_UE_COOKIE_DOMAIN: "odl.local" + MITOL_UE_BASE_URL: "http://localhost:8073" + MITOL_UE_HOSTNAME: "ue.odl.local" + MITOL_UE_JWT_SECRET: "" + MITOL_UE_USE_S3: "False" - name: Upload coverage to CodeCov uses: codecov/codecov-action@v3.1.4 with: file: ./coverage.xml - javascript-tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "18.18.2" - cache: "yarn" - - - name: Setup environment - run: sudo apt-get install libelf1 - - - name: Install dependencies - run: yarn install --immutable - - - name: Webpack build - run: yarn run build - - - name: Lints - run: yarn run lint-check - - - name: Scss lint - run: yarn run scss-lint - - - name: Typecheck - run: yarn run typecheck - - - name: Get number of CPU cores - id: cpu-cores - uses: SimenB/github-actions-cpu-cores@v1 - - - name: Tests - run: yarn test --max-workers ${{ steps.cpu-cores.outputs.count }} - env: - CODECOV: true - NODE_ENV: test - - - name: Upload coverage to CodeCov - uses: codecov/codecov-action@v3.1.4 - with: - file: coverage/lcov.info - openapi-generated-client-check: # This job checks that the output of openapi-generator-typescript-axios that # is checked into version control is up-to-date. From e1e40117a355d65ed91ef77c33c5877ebca74448 Mon Sep 17 00:00:00 2001 From: James Kachel Date: Wed, 17 Jan 2024 09:08:05 -0600 Subject: [PATCH 2/6] maybe put it in the right place, that might be helpful --- .github/{ => workflows}/ci.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{ => workflows}/ci.yml (100%) diff --git a/.github/ci.yml b/.github/workflows/ci.yml similarity index 100% rename from .github/ci.yml rename to .github/workflows/ci.yml From 7f6d232677b475e57fdfb9c34c8bedcc52660bc2 Mon Sep 17 00:00:00 2001 From: James Kachel Date: Wed, 17 Jan 2024 10:29:36 -0600 Subject: [PATCH 3/6] Updating openapi stuff, updating pre-commit to ignore frontend stuff for now --- .github/workflows/ci.yml | 7 - .pre-commit-config.yaml | 74 ++-- .../src/generated/.openapi-generator/FILES | 1 - frontends/api/src/generated/api.ts | 338 +++++++++++++++--- openapi.yaml | 168 +++++++-- 5 files changed, 471 insertions(+), 117 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 936d773c..42d0cc81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,13 +89,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "18.18.2" - cache: "yarn" - - - name: Install dependencies - run: yarn install --immutable - name: Generate Fresh API Client uses: openapi-generators/openapitools-generator-action@v1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5bdfabb5..12e75e8d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,8 @@ --- # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks +# A bunch of frontend related stuff is commented out here - this is because we don't +# have a frontend yet. ci: skip: - prettier-django @@ -19,22 +21,22 @@ repos: - id: check-merge-conflict - id: check-toml - id: debug-statements - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.0.3 - hooks: - - id: prettier - types_or: - [javascript, jsx, ts, tsx, json, scss, sass, css, yaml, markdown] - args: - - --no-config - - --no-semi - - id: prettier - alias: prettier-django - name: prettier-django - types: [html] - additional_dependencies: - - prettier - - prettier-plugin-django-alpine + # - repo: https://github.com/pre-commit/mirrors-prettier + # rev: v3.0.3 + # hooks: + # - id: prettier + # types_or: + # [javascript, jsx, ts, tsx, json, scss, sass, css, yaml, markdown] + # args: + # - --no-config + # - --no-semi + # - id: prettier + # alias: prettier-django + # name: prettier-django + # types: [html] + # additional_dependencies: + # - prettier + # - prettier-plugin-django-alpine - repo: https://github.com/scop/pre-commit-shfmt rev: v3.7.0-1 hooks: @@ -73,26 +75,26 @@ repos: - id: ruff-format - id: ruff args: [--extend-ignore=D1, --fix] - - repo: local - hooks: - - id: eslint - name: eslint - description: "Lint JS/TS files and apply automatic fixes" - entry: npx eslint --fix - language: node - types_or: [javascript, jsx, ts, tsx] - args: [] - exclude: "(node_modules/|.yarn/)" - require_serial: false - - id: scss-lint - name: scss-lint - description: "Lint SCSS files" - entry: npx stylelint --allow-empty-input --fix - language: node - types: [scss] - args: [] - exclude: node_modules/ - require_serial: false + # - repo: local + # hooks: + # - id: eslint + # name: eslint + # description: "Lint JS/TS files and apply automatic fixes" + # entry: npx eslint --fix + # language: node + # types_or: [javascript, jsx, ts, tsx] + # args: [] + # exclude: "(node_modules/|.yarn/)" + # require_serial: false + # - id: scss-lint + # name: scss-lint + # description: "Lint SCSS files" + # entry: npx stylelint --allow-empty-input --fix + # language: node + # types: [scss] + # args: [] + # exclude: node_modules/ + # require_serial: false - repo: https://github.com/shellcheck-py/shellcheck-py rev: v0.9.0.6 hooks: diff --git a/frontends/api/src/generated/.openapi-generator/FILES b/frontends/api/src/generated/.openapi-generator/FILES index 16b445ee..a80cd4f0 100644 --- a/frontends/api/src/generated/.openapi-generator/FILES +++ b/frontends/api/src/generated/.openapi-generator/FILES @@ -1,6 +1,5 @@ .gitignore .npmignore -.openapi-generator-ignore api.ts base.ts common.ts diff --git a/frontends/api/src/generated/api.ts b/frontends/api/src/generated/api.ts index b126817c..55786959 100644 --- a/frontends/api/src/generated/api.ts +++ b/frontends/api/src/generated/api.ts @@ -50,19 +50,37 @@ export interface IntegratedSystem { * @type {string} * @memberof IntegratedSystem */ - name: string + deleted_on: string | null + /** + * + * @type {boolean} + * @memberof IntegratedSystem + */ + deleted_by_cascade: boolean /** * * @type {string} * @memberof IntegratedSystem */ - description?: string + created_on: string /** * - * @type {boolean} + * @type {string} * @memberof IntegratedSystem */ - is_active?: boolean + updated_on: string + /** + * + * @type {string} + * @memberof IntegratedSystem + */ + name: string + /** + * + * @type {string} + * @memberof IntegratedSystem + */ + description?: string /** * * @type {string} @@ -70,6 +88,68 @@ export interface IntegratedSystem { */ api_key?: string } +/** + * + * @export + * @interface PaginatedIntegratedSystemList + */ +export interface PaginatedIntegratedSystemList { + /** + * + * @type {number} + * @memberof PaginatedIntegratedSystemList + */ + count?: number + /** + * + * @type {string} + * @memberof PaginatedIntegratedSystemList + */ + next?: string | null + /** + * + * @type {string} + * @memberof PaginatedIntegratedSystemList + */ + previous?: string | null + /** + * + * @type {Array} + * @memberof PaginatedIntegratedSystemList + */ + results?: Array +} +/** + * + * @export + * @interface PaginatedProductList + */ +export interface PaginatedProductList { + /** + * + * @type {number} + * @memberof PaginatedProductList + */ + count?: number + /** + * + * @type {string} + * @memberof PaginatedProductList + */ + next?: string | null + /** + * + * @type {string} + * @memberof PaginatedProductList + */ + previous?: string | null + /** + * + * @type {Array} + * @memberof PaginatedProductList + */ + results?: Array +} /** * Serializer for IntegratedSystem model. * @export @@ -87,19 +167,37 @@ export interface PatchedIntegratedSystem { * @type {string} * @memberof PatchedIntegratedSystem */ - name?: string + deleted_on?: string | null + /** + * + * @type {boolean} + * @memberof PatchedIntegratedSystem + */ + deleted_by_cascade?: boolean /** * * @type {string} * @memberof PatchedIntegratedSystem */ - description?: string + created_on?: string /** * - * @type {boolean} + * @type {string} + * @memberof PatchedIntegratedSystem + */ + updated_on?: string + /** + * + * @type {string} + * @memberof PatchedIntegratedSystem + */ + name?: string + /** + * + * @type {string} * @memberof PatchedIntegratedSystem */ - is_active?: boolean + description?: string /** * * @type {string} @@ -119,6 +217,30 @@ export interface PatchedProduct { * @memberof PatchedProduct */ id?: number + /** + * + * @type {string} + * @memberof PatchedProduct + */ + deleted_on?: string | null + /** + * + * @type {boolean} + * @memberof PatchedProduct + */ + deleted_by_cascade?: boolean + /** + * + * @type {string} + * @memberof PatchedProduct + */ + created_on?: string + /** + * + * @type {string} + * @memberof PatchedProduct + */ + updated_on?: string /** * SKU of the product. * @type {string} @@ -143,18 +265,12 @@ export interface PatchedProduct { * @memberof PatchedProduct */ description?: string - /** - * Controls visibility of the product in the app. - * @type {boolean} - * @memberof PatchedProduct - */ - is_active?: boolean /** * System-specific data for the product (in JSON). - * @type {{ [key: string]: any; }} + * @type {any} * @memberof PatchedProduct */ - system_data?: { [key: string]: any } | null + system_data?: any | null /** * Owner system of the product. * @type {number} @@ -174,6 +290,30 @@ export interface Product { * @memberof Product */ id: number + /** + * + * @type {string} + * @memberof Product + */ + deleted_on: string | null + /** + * + * @type {boolean} + * @memberof Product + */ + deleted_by_cascade: boolean + /** + * + * @type {string} + * @memberof Product + */ + created_on: string + /** + * + * @type {string} + * @memberof Product + */ + updated_on: string /** * SKU of the product. * @type {string} @@ -198,18 +338,12 @@ export interface Product { * @memberof Product */ description: string - /** - * Controls visibility of the product in the app. - * @type {boolean} - * @memberof Product - */ - is_active?: boolean /** * System-specific data for the product (in JSON). - * @type {{ [key: string]: any; }} + * @type {any} * @memberof Product */ - system_data?: { [key: string]: any } | null + system_data?: any | null /** * Owner system of the product. * @type {number} @@ -242,7 +376,7 @@ export const IntegratedSystemApiAxiosParamCreator = function ( "IntegratedSystem", IntegratedSystem, ) - const localVarPath = `/v0/integrated_system/` + const localVarPath = `/integrated_system/` // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL) let baseOptions @@ -293,7 +427,7 @@ export const IntegratedSystemApiAxiosParamCreator = function ( ): Promise => { // verify required parameter 'id' is not null or undefined assertParamExists("integratedSystemDestroy", "id", id) - const localVarPath = `/v0/integrated_system/{id}/`.replace( + const localVarPath = `/integrated_system/{id}/`.replace( `{${"id"}}`, encodeURIComponent(String(id)), ) @@ -330,13 +464,17 @@ export const IntegratedSystemApiAxiosParamCreator = function ( }, /** * Viewset for IntegratedSystem model. + * @param {number} [limit] Number of results to return per page. + * @param {number} [offset] The initial index from which to return the results. * @param {*} [options] Override http request option. * @throws {RequiredError} */ integratedSystemList: async ( + limit?: number, + offset?: number, options: AxiosRequestConfig = {}, ): Promise => { - const localVarPath = `/v0/integrated_system/` + const localVarPath = `/integrated_system/` // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL) let baseOptions @@ -354,6 +492,14 @@ export const IntegratedSystemApiAxiosParamCreator = function ( // authentication cookieAuth required + if (limit !== undefined) { + localVarQueryParameter["limit"] = limit + } + + if (offset !== undefined) { + localVarQueryParameter["offset"] = offset + } + setSearchParams(localVarUrlObj, localVarQueryParameter) let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {} @@ -382,7 +528,7 @@ export const IntegratedSystemApiAxiosParamCreator = function ( ): Promise => { // verify required parameter 'id' is not null or undefined assertParamExists("integratedSystemPartialUpdate", "id", id) - const localVarPath = `/v0/integrated_system/{id}/`.replace( + const localVarPath = `/integrated_system/{id}/`.replace( `{${"id"}}`, encodeURIComponent(String(id)), ) @@ -436,7 +582,7 @@ export const IntegratedSystemApiAxiosParamCreator = function ( ): Promise => { // verify required parameter 'id' is not null or undefined assertParamExists("integratedSystemRetrieve", "id", id) - const localVarPath = `/v0/integrated_system/{id}/`.replace( + const localVarPath = `/integrated_system/{id}/`.replace( `{${"id"}}`, encodeURIComponent(String(id)), ) @@ -491,7 +637,7 @@ export const IntegratedSystemApiAxiosParamCreator = function ( "IntegratedSystem", IntegratedSystem, ) - const localVarPath = `/v0/integrated_system/{id}/`.replace( + const localVarPath = `/integrated_system/{id}/`.replace( `{${"id"}}`, encodeURIComponent(String(id)), ) @@ -594,19 +740,27 @@ export const IntegratedSystemApiFp = function (configuration?: Configuration) { }, /** * Viewset for IntegratedSystem model. + * @param {number} [limit] Number of results to return per page. + * @param {number} [offset] The initial index from which to return the results. * @param {*} [options] Override http request option. * @throws {RequiredError} */ async integratedSystemList( + limit?: number, + offset?: number, options?: AxiosRequestConfig, ): Promise< ( axios?: AxiosInstance, basePath?: string, - ) => AxiosPromise> + ) => AxiosPromise > { const localVarAxiosArgs = - await localVarAxiosParamCreator.integratedSystemList(options) + await localVarAxiosParamCreator.integratedSystemList( + limit, + offset, + options, + ) return createRequestFunction( localVarAxiosArgs, globalAxios, @@ -742,14 +896,20 @@ export const IntegratedSystemApiFactory = function ( }, /** * Viewset for IntegratedSystem model. + * @param {IntegratedSystemApiIntegratedSystemListRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ integratedSystemList( + requestParameters: IntegratedSystemApiIntegratedSystemListRequest = {}, options?: AxiosRequestConfig, - ): AxiosPromise> { + ): AxiosPromise { return localVarFp - .integratedSystemList(options) + .integratedSystemList( + requestParameters.limit, + requestParameters.offset, + options, + ) .then((request) => request(axios, basePath)) }, /** @@ -833,6 +993,27 @@ export interface IntegratedSystemApiIntegratedSystemDestroyRequest { readonly id: number } +/** + * Request parameters for integratedSystemList operation in IntegratedSystemApi. + * @export + * @interface IntegratedSystemApiIntegratedSystemListRequest + */ +export interface IntegratedSystemApiIntegratedSystemListRequest { + /** + * Number of results to return per page. + * @type {number} + * @memberof IntegratedSystemApiIntegratedSystemList + */ + readonly limit?: number + + /** + * The initial index from which to return the results. + * @type {number} + * @memberof IntegratedSystemApiIntegratedSystemList + */ + readonly offset?: number +} + /** * Request parameters for integratedSystemPartialUpdate operation in IntegratedSystemApi. * @export @@ -930,13 +1111,21 @@ export class IntegratedSystemApi extends BaseAPI { /** * Viewset for IntegratedSystem model. + * @param {IntegratedSystemApiIntegratedSystemListRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof IntegratedSystemApi */ - public integratedSystemList(options?: AxiosRequestConfig) { + public integratedSystemList( + requestParameters: IntegratedSystemApiIntegratedSystemListRequest = {}, + options?: AxiosRequestConfig, + ) { return IntegratedSystemApiFp(this.configuration) - .integratedSystemList(options) + .integratedSystemList( + requestParameters.limit, + requestParameters.offset, + options, + ) .then((request) => request(this.axios, this.basePath)) } @@ -1017,7 +1206,7 @@ export const ProductApiAxiosParamCreator = function ( ): Promise => { // verify required parameter 'Product' is not null or undefined assertParamExists("productCreate", "Product", Product) - const localVarPath = `/v0/product/` + const localVarPath = `/product/` // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL) let baseOptions @@ -1068,7 +1257,7 @@ export const ProductApiAxiosParamCreator = function ( ): Promise => { // verify required parameter 'id' is not null or undefined assertParamExists("productDestroy", "id", id) - const localVarPath = `/v0/product/{id}/`.replace( + const localVarPath = `/product/{id}/`.replace( `{${"id"}}`, encodeURIComponent(String(id)), ) @@ -1105,13 +1294,17 @@ export const ProductApiAxiosParamCreator = function ( }, /** * Viewset for Product model. + * @param {number} [limit] Number of results to return per page. + * @param {number} [offset] The initial index from which to return the results. * @param {*} [options] Override http request option. * @throws {RequiredError} */ productList: async ( + limit?: number, + offset?: number, options: AxiosRequestConfig = {}, ): Promise => { - const localVarPath = `/v0/product/` + const localVarPath = `/product/` // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL) let baseOptions @@ -1129,6 +1322,14 @@ export const ProductApiAxiosParamCreator = function ( // authentication cookieAuth required + if (limit !== undefined) { + localVarQueryParameter["limit"] = limit + } + + if (offset !== undefined) { + localVarQueryParameter["offset"] = offset + } + setSearchParams(localVarUrlObj, localVarQueryParameter) let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {} @@ -1157,7 +1358,7 @@ export const ProductApiAxiosParamCreator = function ( ): Promise => { // verify required parameter 'id' is not null or undefined assertParamExists("productPartialUpdate", "id", id) - const localVarPath = `/v0/product/{id}/`.replace( + const localVarPath = `/product/{id}/`.replace( `{${"id"}}`, encodeURIComponent(String(id)), ) @@ -1211,7 +1412,7 @@ export const ProductApiAxiosParamCreator = function ( ): Promise => { // verify required parameter 'id' is not null or undefined assertParamExists("productRetrieve", "id", id) - const localVarPath = `/v0/product/{id}/`.replace( + const localVarPath = `/product/{id}/`.replace( `{${"id"}}`, encodeURIComponent(String(id)), ) @@ -1262,7 +1463,7 @@ export const ProductApiAxiosParamCreator = function ( assertParamExists("productUpdate", "id", id) // verify required parameter 'Product' is not null or undefined assertParamExists("productUpdate", "Product", Product) - const localVarPath = `/v0/product/{id}/`.replace( + const localVarPath = `/product/{id}/`.replace( `{${"id"}}`, encodeURIComponent(String(id)), ) @@ -1362,16 +1563,26 @@ export const ProductApiFp = function (configuration?: Configuration) { }, /** * Viewset for Product model. + * @param {number} [limit] Number of results to return per page. + * @param {number} [offset] The initial index from which to return the results. * @param {*} [options] Override http request option. * @throws {RequiredError} */ async productList( + limit?: number, + offset?: number, options?: AxiosRequestConfig, ): Promise< - (axios?: AxiosInstance, basePath?: string) => AxiosPromise> + ( + axios?: AxiosInstance, + basePath?: string, + ) => AxiosPromise > { - const localVarAxiosArgs = - await localVarAxiosParamCreator.productList(options) + const localVarAxiosArgs = await localVarAxiosParamCreator.productList( + limit, + offset, + options, + ) return createRequestFunction( localVarAxiosArgs, globalAxios, @@ -1499,12 +1710,16 @@ export const ProductApiFactory = function ( }, /** * Viewset for Product model. + * @param {ProductApiProductListRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - productList(options?: AxiosRequestConfig): AxiosPromise> { + productList( + requestParameters: ProductApiProductListRequest = {}, + options?: AxiosRequestConfig, + ): AxiosPromise { return localVarFp - .productList(options) + .productList(requestParameters.limit, requestParameters.offset, options) .then((request) => request(axios, basePath)) }, /** @@ -1584,6 +1799,27 @@ export interface ProductApiProductDestroyRequest { readonly id: number } +/** + * Request parameters for productList operation in ProductApi. + * @export + * @interface ProductApiProductListRequest + */ +export interface ProductApiProductListRequest { + /** + * Number of results to return per page. + * @type {number} + * @memberof ProductApiProductList + */ + readonly limit?: number + + /** + * The initial index from which to return the results. + * @type {number} + * @memberof ProductApiProductList + */ + readonly offset?: number +} + /** * Request parameters for productPartialUpdate operation in ProductApi. * @export @@ -1681,13 +1917,17 @@ export class ProductApi extends BaseAPI { /** * Viewset for Product model. + * @param {ProductApiProductListRequest} requestParameters Request parameters. * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ProductApi */ - public productList(options?: AxiosRequestConfig) { + public productList( + requestParameters: ProductApiProductListRequest = {}, + options?: AxiosRequestConfig, + ) { return ProductApiFp(this.configuration) - .productList(options) + .productList(requestParameters.limit, requestParameters.offset, options) .then((request) => request(this.axios, this.basePath)) } diff --git a/openapi.yaml b/openapi.yaml index ff38fc37..629bf406 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -3,10 +3,23 @@ info: title: '' version: 0.0.0 paths: - /v0/integrated_system/: + /integrated_system/: get: operationId: integrated_system_list description: Viewset for IntegratedSystem model. + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer tags: - integrated_system security: @@ -16,9 +29,7 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/IntegratedSystem' + $ref: '#/components/schemas/PaginatedIntegratedSystemList' description: '' post: operationId: integrated_system_create @@ -46,7 +57,7 @@ paths: schema: $ref: '#/components/schemas/IntegratedSystem' description: '' - /v0/integrated_system/{id}/: + /integrated_system/{id}/: get: operationId: integrated_system_retrieve description: Viewset for IntegratedSystem model. @@ -150,10 +161,23 @@ paths: responses: '204': description: No response body - /v0/product/: + /product/: get: operationId: product_list description: Viewset for Product model. + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer tags: - product security: @@ -163,9 +187,7 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/Product' + $ref: '#/components/schemas/PaginatedProductList' description: '' post: operationId: product_create @@ -193,7 +215,7 @@ paths: schema: $ref: '#/components/schemas/Product' description: '' - /v0/product/{id}/: + /product/{id}/: get: operationId: product_retrieve description: Viewset for Product model. @@ -306,18 +328,76 @@ components: id: type: integer readOnly: true + deleted_on: + type: string + format: date-time + readOnly: true + nullable: true + deleted_by_cascade: + type: boolean + readOnly: true + created_on: + type: string + format: date-time + readOnly: true + updated_on: + type: string + format: date-time + readOnly: true name: type: string maxLength: 255 description: type: string - is_active: - type: boolean api_key: type: string required: + - created_on + - deleted_by_cascade + - deleted_on - id - name + - updated_on + PaginatedIntegratedSystemList: + type: object + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/IntegratedSystem' + PaginatedProductList: + type: object + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Product' PatchedIntegratedSystem: type: object description: Serializer for IntegratedSystem model. @@ -325,13 +405,27 @@ components: id: type: integer readOnly: true + deleted_on: + type: string + format: date-time + readOnly: true + nullable: true + deleted_by_cascade: + type: boolean + readOnly: true + created_on: + type: string + format: date-time + readOnly: true + updated_on: + type: string + format: date-time + readOnly: true name: type: string maxLength: 255 description: type: string - is_active: - type: boolean api_key: type: string PatchedProduct: @@ -341,6 +435,22 @@ components: id: type: integer readOnly: true + deleted_on: + type: string + format: date-time + readOnly: true + nullable: true + deleted_by_cascade: + type: boolean + readOnly: true + created_on: + type: string + format: date-time + readOnly: true + updated_on: + type: string + format: date-time + readOnly: true sku: type: string description: SKU of the product. @@ -357,12 +467,7 @@ components: description: type: string description: Long description of the product. - is_active: - type: boolean - description: Controls visibility of the product in the app. system_data: - type: object - additionalProperties: {} nullable: true description: System-specific data for the product (in JSON). system: @@ -375,6 +480,22 @@ components: id: type: integer readOnly: true + deleted_on: + type: string + format: date-time + readOnly: true + nullable: true + deleted_by_cascade: + type: boolean + readOnly: true + created_on: + type: string + format: date-time + readOnly: true + updated_on: + type: string + format: date-time + readOnly: true sku: type: string description: SKU of the product. @@ -391,24 +512,23 @@ components: description: type: string description: Long description of the product. - is_active: - type: boolean - description: Controls visibility of the product in the app. system_data: - type: object - additionalProperties: {} nullable: true description: System-specific data for the product (in JSON). system: type: integer description: Owner system of the product. required: + - created_on + - deleted_by_cascade + - deleted_on - description - id - name - price - sku - system + - updated_on securitySchemes: cookieAuth: type: apiKey From 201890dfaf0fa2af0e76803a9cb066bb63ce5414 Mon Sep 17 00:00:00 2001 From: James Kachel Date: Wed, 17 Jan 2024 10:38:37 -0600 Subject: [PATCH 4/6] some more CI changes --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42d0cc81..058891a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,6 +72,7 @@ jobs: MITOL_UE_HOSTNAME: "ue.odl.local" MITOL_UE_JWT_SECRET: "" MITOL_UE_USE_S3: "False" + MITOL_UE_DB_DISABLE_SSL: "True" - name: Upload coverage to CodeCov uses: codecov/codecov-action@v3.1.4 @@ -100,8 +101,6 @@ jobs: --output $GENERATOR_OUTPUT_DIR_CI \ --ignore-file-override $GENERATOR_IGNORE_FILE \ -c scripts/openapi-configs/typescript-axios.yaml - - name: Format freshly generated client - run: npx prettier $GENERATOR_OUTPUT_DIR_CI/**/*.ts --no-semi --write - name: Check VC client is up-to-date run: | diff $GENERATOR_OUTPUT_DIR_CI $GENERATOR_OUTPUT_DIR_VC \ From 2b6ea1672704409718a177e372b252f216a3c7dc Mon Sep 17 00:00:00 2001 From: James Kachel Date: Wed, 17 Jan 2024 10:41:27 -0600 Subject: [PATCH 5/6] pulling the separate openapi job - this gets checked in python-tests anyway --- .github/workflows/ci.yml | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 058891a6..3a2d8a6a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,30 +78,3 @@ jobs: uses: codecov/codecov-action@v3.1.4 with: file: ./coverage.xml - - openapi-generated-client-check: - # This job checks that the output of openapi-generator-typescript-axios that - # is checked into version control is up-to-date. - env: - OPENAPI_SCHEMA: ./openapi.yaml - GENERATOR_IGNORE_FILE: ./frontends/api/.openapi-generator-ignore - GENERATOR_OUTPUT_DIR_CI: ./frontends/api/tmp/generated - GENERATOR_OUTPUT_DIR_VC: ./frontends/api/src/generated - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Generate Fresh API Client - uses: openapi-generators/openapitools-generator-action@v1 - with: - generator: typescript-axios - openapi-file: ./openapi.yaml - generator-tag: v6.6.0 - command-args: | - --output $GENERATOR_OUTPUT_DIR_CI \ - --ignore-file-override $GENERATOR_IGNORE_FILE \ - -c scripts/openapi-configs/typescript-axios.yaml - - name: Check VC client is up-to-date - run: | - diff $GENERATOR_OUTPUT_DIR_CI $GENERATOR_OUTPUT_DIR_VC \ - || { echo "OpenAPI spec is out of date. Please regenerate via ./scripts/generate_openapi.sh"; exit 1; } From dd39b157c00787b353e9e9d0728ee90a9371e6b4 Mon Sep 17 00:00:00 2001 From: James Kachel Date: Wed, 17 Jan 2024 11:11:16 -0600 Subject: [PATCH 6/6] Updating docs --- README.md | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 75145468..3733fdfc 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,10 @@ This application provides a central system to handle ecommerce activities across - [MIT OL Unified Ecommerce](#mit-ol-unified-ecommerce) - [Initial Setup](#initial-setup) - [Configure required `.env` settings](#configure-required-env-settings) - - [Loading Data](#loading-data) + - [Loading and Accessing Data](#loading-and-accessing-data) - [Code Generation](#code-generation) - [Committing \& Formatting](#committing--formatting) - [Optional Setup](#optional-setup) - - [Enabling email](#enabling-email) - [Running the app in a notebook](#running-the-app-in-a-notebook) ## Initial Setup @@ -24,24 +23,33 @@ Run through those steps **including the addition of `/etc/hosts` aliases and the The following settings must be configured before running the app: -- `MAILGUN_KEY` and `MAILGUN_SENDER_DOMAIN` - - You can set these values to any non-empty string value if email-sending functionality - is not needed. It's recommended that you eventually configure the site to be able - to send emails. Those configuration steps can be found [below](#enabling-email). - - `MITOL_UE_HOSTNAME` Sets the hostname required by webpack for building the frontend. Should likely be whatever you set - the host to in your /etc/hosts or the hostname that you're accessing it from. Likely `oe.odl.local`. + the host to in your /etc/hosts or the hostname that you're accessing it from. Likely `ue.odl.local`. - `SECRET_KEY` Sets the Django secret for the application. This just needs to be a random string. -### Loading Data +### Loading and Accessing Data + +You'll need an integrated system and product for that system to be able to do much of anything. Once you've done initial setup, run these commands: + +* Create an integrated system: `./manage.py add_system -d ` +* Create a product: `./manage.py manage_product add -s --sku --name --description --price ` + +The `add_system` command will generate an API key for the system's use. You can add as many systems as you wish. + +> Alternatively, you can create these records through the Django Admin, but be advised that it won't create the API key for you. The management command uses a UUID for the key but any value will do, as long as it's unique. + +You can interact with the API directly through the Swagger interface: `/api/schema/swagger-ui/` + +The system also exposes a Redoc version of the API at `/api/schema/redoc/` -_TBD_ +Navigating to an API endpoint in the browser should also get you the normal DRF interface as well. + +> At this point we don't have API auth outside of Django sessions, so generated API keys don't do anything yet. There's no other frontend to this application at this point either. ## Code Generation @@ -77,21 +85,6 @@ pre-commit init-templatedir ~/.git-template Described below are some setup steps that are not strictly necessary for running Unified Ecommerce. -### Enabling email - -The app is usable without email-sending capability, but there is a lot of app functionality -that depends on it. The following variables will need to be set in your `.env` file - -please reach out to a fellow developer or devops for the correct values. - -``` -MAILGUN_SENDER_DOMAIN -MAILGUN_URL -MAILGUN_KEY -``` - -Additionally, you'll need to set `MAILGUN_RECIPIENT_OVERRIDE` to your own email address so -any emails sent from the app will be delivered to you. - ### Running the app in a notebook This repo includes a config for running a [Jupyter notebook](https://jupyter.org/) in a Docker container. This enables you to do in a Jupyter notebook anything you might otherwise do in a Django shell. To get started: