diff --git a/.github/workflows/cleanup-registry.yml b/.github/workflows/cleanup-registry.yml index da476d12a..32b82f8df 100644 --- a/.github/workflows/cleanup-registry.yml +++ b/.github/workflows/cleanup-registry.yml @@ -5,20 +5,14 @@ on: - cron: '0 0 * * 1' # https://crontab.guru/#0_0_*_*_1 workflow_dispatch: -env: - IMAGE_NAMES: amber-ui - jobs: cleanup: name: Cleanup runs-on: ubuntu-latest steps: - - name: Delete old versions - uses: snok/container-retention-policy@f617f1ca161a52bce48417eedd76924e71d0b4d9 # v2.1.0 + - name: Delete untagged images + uses: actions/delete-package-versions@0d39a63126868f5eefaa47169615edd3c0f61e20 # v4.1.1 with: - image-names: ${{ env.IMAGE_NAMES }} - cut-off: 2 days ago UTC - account-type: org - org-name: ${{ github.repository_owner }} - skip-tags: latest,staging - token: ${{ secrets.GH_PAT }} + package-name: ${{ github.event.repository.name }} + package-type: container + delete-only-untagged-versions: true diff --git a/.github/workflows/continuous-delivery.yml b/.github/workflows/continuous-delivery.yml index bb0653006..97682581a 100644 --- a/.github/workflows/continuous-delivery.yml +++ b/.github/workflows/continuous-delivery.yml @@ -41,7 +41,7 @@ jobs: stage: ${{ steps.get_metadata.outputs.stage }} steps: - name: Checkout code - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get metadata id: get_metadata @@ -85,8 +85,8 @@ jobs: fi - name: Checkout code - if: fromJSON(needs.metadata.outputs.has_diff) || github.event.inputs.ignore_metadata_diff - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + if: fromJSON(needs.metadata.outputs.has_diff) + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run merge if: fromJSON(needs.metadata.outputs.has_diff) || github.event.inputs.ignore_metadata_diff @@ -111,6 +111,8 @@ jobs: uses: csvalpha/amber-ui/.github/workflows/continuous-integration.yml@staging with: sha: ${{ needs.merge.outputs.sha }} + secrets: + codecov_token: ${{ secrets.CODECOV_TOKEN }} publish_image: name: Publish Image @@ -141,7 +143,7 @@ jobs: fi - name: Checkout code - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ needs.merge.outputs.sha }} diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 71a22b9a7..e58335c31 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -11,6 +11,10 @@ on: description: The commit SHA to run the workflow on required: false type: string + secrets: + codecov_token: + description: Codecov token + required: true jobs: build: @@ -18,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.sha }} @@ -35,7 +39,7 @@ jobs: needs: build steps: - name: Checkout code - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.sha }} @@ -70,6 +74,11 @@ jobs: runs-on: ubuntu-latest needs: build steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ inputs.sha }} + - name: Load test image uses: guidojw/actions/load-docker-image@abb0ee8d1336edf73383f2e5a09abd3a22f25b13 # v1.3.3 with: @@ -77,4 +86,20 @@ jobs: - name: Test run: | - docker run -e CI=true -t app yarn test:ember + mkdir coverage + docker run -e CI=true -e COVERAGE=true -v "$(pwd)"'/coverage:/opt/app/coverage' app yarn test:ember + + - name: Upload coverage report to Codecov + if: ${{ !cancelled() }} + uses: codecov/codecov-action@54bcd8715eee62d40e33596ef5e8f0f48dbbccab # v4.1.0 + with: + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Upload coverage report artifact + if: ${{ !cancelled() }} + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + with: + name: coverage + path: coverage/ + if-no-files-found: error diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml index c9be26317..6b8d1c89b 100644 --- a/.github/workflows/publish-image.yml +++ b/.github/workflows/publish-image.yml @@ -55,7 +55,7 @@ jobs: needs: metadata steps: - name: Checkout code - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.sha }} fetch-depth: 0 @@ -64,7 +64,7 @@ jobs: uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2.5.0 - name: Login to GitHub Container Registry - uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # tag=v2.1.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: registry: ${{ vars.DOCKER_REGISTRY_URL }} username: ${{ github.repository_owner }} @@ -72,7 +72,7 @@ jobs: - name: Build and push image id: build_push_image - uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4.0.0 + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 with: push: true context: . diff --git a/README.md b/README.md index 33c94fb5f..a2300eb69 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Continuous Integration](https://github.com/csvalpha/amber-ui/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/csvalpha/amber-ui/actions/workflows/continuous-integration.yml) [![Continuous Delivery](https://github.com/csvalpha/amber-ui/actions/workflows/continuous-delivery.yml/badge.svg)](https://github.com/csvalpha/amber-ui/actions/workflows/continuous-delivery.yml) +[![codecov](https://codecov.io/gh/csvalpha/amber-ui/graph/badge.svg?token=GMTXV28YQF)](https://codecov.io/gh/csvalpha/amber-ui) ## Prerequisites diff --git a/app/abilities/photo-tag.js b/app/abilities/photo-tag.js new file mode 100644 index 000000000..11f00a498 --- /dev/null +++ b/app/abilities/photo-tag.js @@ -0,0 +1,36 @@ +import { Ability } from 'ember-can'; +import { isNone } from '@ember/utils'; + +export default class PhotoTag extends Ability { + get canShow() { + return this.session.hasPermission('photo-tag.read'); + } + + get canCreate() { + return this.session.hasPermission('photo-tag.create'); + } + + get canDestroy() { + return ( + this.session.hasPermission('photo-tag.destroy') || + this.isTagOwner(this.model) || + this.isTagged(this.model) + ); + } + + isTagOwner(photoTag) { + const { currentUser } = this.session; + return ( + !isNone(currentUser) && + photoTag.get('author.id') === currentUser.get('id') + ); + } + + isTagged(photoTag) { + const { currentUser } = this.session; + return ( + !isNone(currentUser) && + photoTag.get('taggedUser.id') === currentUser.get('id') + ); + } +} diff --git a/app/abilities/photo.js b/app/abilities/photo.js index 141478220..92ee0cff6 100644 --- a/app/abilities/photo.js +++ b/app/abilities/photo.js @@ -11,4 +11,8 @@ export default class Photo extends Ability { this.model.photoAlbum.get('publiclyVisible') ); } + + get canShowPhotoTags() { + return this.session.hasPermission('photo-tag.read'); + } } diff --git a/app/abilities/quickpost-message.js b/app/abilities/quickpost-message.js deleted file mode 100644 index 5d6cdb029..000000000 --- a/app/abilities/quickpost-message.js +++ /dev/null @@ -1,11 +0,0 @@ -import { Ability } from 'ember-can'; - -export default class QuickpostMessage extends Ability { - get canShow() { - return this.session.hasPermission('quickpost-message.read'); - } - - get canDestroy() { - return this.session.hasPermission('quickpost-message.destroy'); - } -} diff --git a/app/abilities/room-advert.js b/app/abilities/room-advert.js new file mode 100644 index 000000000..d54caeaf6 --- /dev/null +++ b/app/abilities/room-advert.js @@ -0,0 +1,31 @@ +import { isNone } from '@ember/utils'; +import { Ability } from 'ember-can'; + +export default class RoomAdvert extends Ability { + get canCreate() { + return this.session.hasPermission('room-advert.create'); + } + + get canShow() { + return this.session.hasPermission('room-advert.read'); + } + + get canDestroy() { + return ( + this.session.hasPermission('room-advert.destroy') || + this.isRoomAdvertOwner(this.model) + ); + } + + get canEdit() { + return ( + this.session.hasPermission('room-advert.update') || + this.isRoomAdvertOwner(this.model) + ); + } + + isRoomAdvertOwner(roomAdvert) { + const { currentUser } = this.session; + return !isNone(currentUser) && roomAdvert.isOwner(currentUser); + } +} diff --git a/app/adapters/application.js b/app/adapters/application.js index d605adac7..b3b5ec88b 100644 --- a/app/adapters/application.js +++ b/app/adapters/application.js @@ -15,6 +15,7 @@ export default class ApplicationAdapter extends JSONAPIAdapter { let headers = {}; if (this.session.isAuthenticated) { headers.Authorization = `Bearer ${this.session.data.authenticated.access_token}`; + document.documentElement.classList.add('authenticated'); } return headers; diff --git a/app/components/advertisement-tool.js b/app/components/advertisement-tool.js index 33462fd0a..953b4a57f 100644 --- a/app/components/advertisement-tool.js +++ b/app/components/advertisement-tool.js @@ -21,110 +21,100 @@ export default Component.extend({ { title: 'Qorting.nl', link: 'https://qorting.nl/', - image: 'advertisements/qorting.png', + image: 'advertisements/Qorting.png', full: true, }, { title: 'Sponsorkliks', link: 'https://www.sponsorkliks.com/products/shops.php?club=4509', - image: 'advertisements/sponsorkliks.png', + image: 'advertisements/SponsorKliks.png', full: true, }, { - title: 'StudentenWegwijzer', - link: 'https://www.studentenwegwijzer.nl/enschede/studentenverenigingen/alpha/', - image: 'advertisements/studenten-wegwijzer.png', - full: true, - }, - { - title: 'InShared', - link: 'https://www.inshared.nl/', - image: 'advertisements/inshared.png', + title: 'BeBo Parket', + link: 'https://www.beboparket.nl/', + image: 'advertisements/BeBo.png', }, { - title: 'Led24', - link: 'https://www.led24.nl/led-verlichting/led-tl-buis/', - image: 'advertisements/led24.png', + title: 'Boeketcadeau', + link: 'https://www.boeketcadeau.nl/', + image: 'advertisements/BoeketCadeau.png', }, { - title: 'Noppies', - link: 'https://www.noppies.com/', - image: 'advertisements/noppies.png', + title: 'Baktotaal', + link: 'https://www.baktotaal.nl/', + image: 'advertisements/Baktotaal.png', }, { - title: 'Rotimshop', - link: 'https://www.rotimshop.nl/', - image: 'advertisements/rotim.png', + title: 'Comfort Producten', + link: 'https://www.comfort-producten.nl/nl/', + image: 'advertisements/ComfortProducts.png', }, { - title: 'Sans Online', - link: 'https://www.sans-online.nl/herenkleding/jassen/', - image: 'advertisements/sans.png', + title: 'Huurzone', + link: 'https://www.huurzone.nl/aanbod/nederland.html', + image: 'advertisements/Huurzone.png', }, { - title: 'Sliponline', - link: 'https://www.sliponline.nl/kinderen/kinder-nachtkleding/kinder-pyjama/', - image: 'advertisements/sliponline.png', + title: 'Inshared', + link: 'https://www.inshared.nl/', + image: 'advertisements/Inshared.png', }, { - title: 'Stellingstunt', - link: 'https://www.stellingstunt.nl/', - image: 'advertisements/stellingstunt.png', + title: 'Ledlampenkopen.nu', + link: 'https://www.ledlampenkopen.nu/', + image: 'advertisements/LedlampenKopen.png', }, { - title: 'Baktotaal Bouwhuis', - link: 'https://www.bouwhuis.com/', - image: 'advertisements/bouwhuis.png', + title: 'Parcel Pro', + link: 'https://parcelpro.nl/', + image: 'advertisements/ParcelPro.png', }, { - title: 'Shops United', - link: 'https://shops-united.nl/', - image: 'advertisements/shops-united.png', + title: 'Bierglazen bedrukken met logo', + alt: 'Bierglazen bedrukken met logo', + link: 'https://www.rikegroup.com/glazen-bedrukken/bierglazen-bedrukken', + image: 'advertisements/Rike_2022.png', }, { - title: 'Urbansofa', - link: 'https://www.urbansofa.nl/', - image: 'advertisements/urbansofa.png', + title: 'Rotimshop', + link: 'https://www.rotimshop.nl/', + image: 'advertisements/RotimShop.png', }, { - title: 'Prefixbroker', - link: 'https://www.prefixbroker.com/', - image: 'advertisements/prefixbroker.png', + title: 'Shops United', + link: 'https://shops-united.nl/', + image: 'advertisements/ShopsUnited.png', }, { - title: 'Van Eyck Shutters', - link: 'https://www.vaneyckshutters.com/', - image: 'advertisements/van-eyck.png', + title: 'Sleiderink', + link: 'https://www.sleiderink.nl/', + image: 'advertisements/Sleiderink.png', }, { - title: 'Verzekering.nl', - link: 'https://www.verzekering.nl/', - image: 'advertisements/verzekering.png', + title: 'Sliponline', + link: 'https://www.sliponline.nl/kinderen/kinder-nachtkleding/kinder-pyjama/', + image: 'advertisements/SlipOnline.png', }, { - title: 'Zantman Kliniek', - link: 'https://www.zantmankliniek.nl/', - image: 'advertisements/zantman.png', + title: 'Stellingstunt', + link: 'https://www.stellingstunt.nl/', + image: 'advertisements/StellingStunt.png', }, { - title: 'Bierglazen bedrukken met logo', - alt: 'Bierglazen bedrukken met logo', - link: 'https://www.rikegroup.com/glazen-bedrukken/bierglazen-bedrukken', - image: 'advertisements/rike.png', + title: 'Traffic Today', + link: 'https://www.traffictoday.nl/', + image: 'advertisements/TrafficToday.jpg', }, { - links: [ - { - link: 'https://www.huurzone.nl/aanbod/nederland.html', - title: 'huurwoningen', - }, - ], + title: 'Verzekering', + link: 'https://www.verzekering.nl/', + image: 'advertisements/VerzekeringNL.png', }, { - title: 'Top 5 Beste Kopen', - alt: 'Vergelijk de beste producten', - link: 'https://www.top5bestekopen.nl', - image: 'advertisements/trendiq.jpg', + title: 'Visser & Visser', + link: 'https://www.visserenvisser.nl/', + image: 'advertisements/Visser&Visser.png', }, ], }); diff --git a/app/components/cards/article-card.hbs b/app/components/cards/article-card.hbs index a126dae8c..8558b4fd7 100644 --- a/app/components/cards/article-card.hbs +++ b/app/components/cards/article-card.hbs @@ -102,7 +102,7 @@ {{#if useMaxHeight}} {{/if}} diff --git a/app/components/cards/photo-album-card.hbs b/app/components/cards/photo-album-card.hbs index d205ca647..5d54d979c 100644 --- a/app/components/cards/photo-album-card.hbs +++ b/app/components/cards/photo-album-card.hbs @@ -5,11 +5,18 @@ src='{{album.albumMediumUrl}}' class='card-img-rounded' /> +

{{album.title}}

{{moment-format album.date 'DD-MM-YYYY'}}

+ {{#if album.amountOfTaggedPhotos}} + + + {{album.amountOfTaggedPhotos}}/{{album.amountOfPhotos}} + + {{/if}}
\ No newline at end of file diff --git a/app/components/cards/public-room-advert-card.hbs b/app/components/cards/public-room-advert-card.hbs new file mode 100644 index 000000000..664c90042 --- /dev/null +++ b/app/components/cards/public-room-advert-card.hbs @@ -0,0 +1,76 @@ +
+
+
+ {{#if (not @collapsed)}} + + {{/if}} +
+
+
+ {{#if @collapsed}} +
+

{{@roomAdvert.houseName}}

+
+
+ {{/if}} + + {{#if @roomAdvert.location}} + + + + + {{/if}} + {{#if @roomAdvert.availableFrom}} + + + + + {{/if}} + + + + +
{{t 'component.public.roomForum.location'}} + + {{@roomAdvert.location}} + +
{{t 'component.public.roomForum.availableFrom'}}{{moment-format @roomAdvert.availableFrom 'DD-M-YYYY'}}
{{t 'component.public.roomForum.contact'}} + {{#if (is-phone @roomAdvert.contact)}} + {{@roomAdvert.contact}} + {{else if (is-email @roomAdvert.contact)}} + {{@roomAdvert.contact}} + {{else if (is-url @roomAdvert.contact)}} + {{@roomAdvert.contact}} + {{else}} + {{@roomAdvert.contact}} + {{/if}} +
+
+ {{#if (and @roomAdvert.coverPhotoUrl @collapsed)}} + + {{/if}} +
+

+ {{markdown-to-html + @roomAdvert.descriptionCamofied + extensions='youtubeEmbed bootstrapTable' + }} +

+

+ {{#if @collapsed}} + + {{/if}} +
+
+
+
\ No newline at end of file diff --git a/app/components/cards/public-room-advert-card.js b/app/components/cards/public-room-advert-card.js new file mode 100644 index 000000000..c75c19361 --- /dev/null +++ b/app/components/cards/public-room-advert-card.js @@ -0,0 +1,11 @@ +import Component from '@glimmer/component'; +import { action } from '@ember/object'; + +export default class PublicRoomAdvertCardComponent extends Component { + @action + open(advert) { + if (this.args.open) { + this.args.open(advert); + } + } +} diff --git a/app/components/cards/room-advert-card.hbs b/app/components/cards/room-advert-card.hbs new file mode 100644 index 000000000..bd6024dab --- /dev/null +++ b/app/components/cards/room-advert-card.hbs @@ -0,0 +1,72 @@ +
+
+ + +
+ +
+

+ {{@roomAdvert.houseName}} +

+

+ + + {{@roomAdvert.author.fullName}} + + +

+
+
+
+ +
+ {{#if @roomAdvert.location}} + + {{/if}} + + {{#if @roomAdvert.availableFrom}} +
+ Beschikbaar vanaf: + {{moment-format @roomAdvert.availableFrom 'DD-M-YYYY'}} +
+ {{/if}} +
+ +
+

+ {{markdown-to-html + @roomAdvert.descriptionCamofied + extensions='youtubeEmbed bootstrapTable' + }} +

+
+ + {{#if @roomAdvert.contact}} +
+
+ Contact: + {{#if (is-phone @roomAdvert.contact)}} + {{@roomAdvert.contact}} + {{else if (is-email @roomAdvert.contact)}} + {{@roomAdvert.contact}} + {{else if (is-url @roomAdvert.contact)}} + {{@roomAdvert.contact}} + {{else}} + {{@roomAdvert.contact}} + {{/if}} +
+
+ {{/if}} +
\ No newline at end of file diff --git a/app/components/forms/room-advert-form.hbs b/app/components/forms/room-advert-form.hbs new file mode 100644 index 000000000..7c9139f01 --- /dev/null +++ b/app/components/forms/room-advert-form.hbs @@ -0,0 +1,81 @@ +
+
+
{{if @model.isNew 'Kamer advertentie aanmaken' 'Kamer advertentie wijzigen'}}
+
+
+
+ + + + + + + + {{#if @model.publiclyVisible}} +
+
+ +
+
+ {{/if}} + + + + + + + +
+
\ No newline at end of file diff --git a/app/components/header-nav.hbs b/app/components/header-nav.hbs index cc2df8113..4740e450e 100644 --- a/app/components/header-nav.hbs +++ b/app/components/header-nav.hbs @@ -1,49 +1,51 @@ -