From c5bfe24d3a906e4f72c7f6fef5d99015d7d5bb56 Mon Sep 17 00:00:00 2001 From: Derek Burgman Date: Thu, 12 May 2022 15:10:44 -0500 Subject: [PATCH] checkpoint: demo --- .../guestbook/guestbookentry.function.spec.ts | 2 +- .../guestbook/guestbookentry.update.ts | 1 - apps/demo-api/src/test/fixture.ts | 2 +- .../src/lib/guestbook/guestbook.query.ts | 6 ++- .../src/lib/guestbook/guestbook.ts | 8 +-- apps/demo-firebase/src/lib/profile/profile.ts | 4 +- .../container/guestbook.view.component.html | 1 + .../store/guestbook.collection.store.ts | 3 +- .../store/guestbook.entry.collection.store.ts | 3 +- ...uestbook.entry.document.store.directive.ts | 3 ++ .../store/guestbook.entry.document.store.ts | 2 +- .../landing/container/layout.component.html | 24 +++++++-- .../landing/container/layout.component.ts | 53 ++++++++++++++----- .../demo/src/app/modules/landing/landing.scss | 39 ++++++++++++++ firestore.rules | 27 +++++++++- .../dbx-web/src/lib/layout/style/_style.scss | 13 ++++- 16 files changed, 160 insertions(+), 31 deletions(-) diff --git a/apps/demo-api/src/app/function/guestbook/guestbookentry.function.spec.ts b/apps/demo-api/src/app/function/guestbook/guestbookentry.function.spec.ts index 922f9afe2..7b9493e6c 100644 --- a/apps/demo-api/src/app/function/guestbook/guestbookentry.function.spec.ts +++ b/apps/demo-api/src/app/function/guestbook/guestbookentry.function.spec.ts @@ -10,7 +10,7 @@ demoApiFunctionContextFactory((f: DemoApiFunctionContextFixture) => { demoAuthorizedUserContext({ f }, (u) => { - demoGuestbookContext({ f, active: true }, (g) => { + demoGuestbookContext({ f, published: true }, (g) => { describe('guestbook is active', () => { diff --git a/apps/demo-api/src/app/function/guestbook/guestbookentry.update.ts b/apps/demo-api/src/app/function/guestbook/guestbookentry.update.ts index de6749906..547d361e9 100644 --- a/apps/demo-api/src/app/function/guestbook/guestbookentry.update.ts +++ b/apps/demo-api/src/app/function/guestbook/guestbookentry.update.ts @@ -10,6 +10,5 @@ export const updateGuestbookEntry = onCallWithDemoNestContext(inAuthContext(asyn const { guestbook: guestbookId } = guestbookEntryUpdateEntry.params; const guestbookEntryDocument = guestbookEntryForUser(nest, guestbookId, uid); - await guestbookEntryUpdateEntry(guestbookEntryDocument); })); diff --git a/apps/demo-api/src/test/fixture.ts b/apps/demo-api/src/test/fixture.ts index 16560d591..a05a15e4a 100644 --- a/apps/demo-api/src/test/fixture.ts +++ b/apps/demo-api/src/test/fixture.ts @@ -152,7 +152,7 @@ export const demoGuestbookContextFactory = () => modelTestContextFactory< await guestbook.accessor.set({ name: params.name ?? 'test', - active: params.active ?? true, + published: params.published ?? true, locked: params.locked ?? false, lockedAt: (params.lockedAt) ?? ((params.locked) ? new Date() : undefined) }); diff --git a/apps/demo-firebase/src/lib/guestbook/guestbook.query.ts b/apps/demo-firebase/src/lib/guestbook/guestbook.query.ts index 64a6c28f3..551784369 100644 --- a/apps/demo-firebase/src/lib/guestbook/guestbook.query.ts +++ b/apps/demo-firebase/src/lib/guestbook/guestbook.query.ts @@ -1,5 +1,9 @@ import { FirestoreQueryConstraint, where } from "@dereekb/firebase"; -export function publishedGuestbookEntries(published = true): FirestoreQueryConstraint { +export function publishedGuestbook(published = true): FirestoreQueryConstraint { + return where('published', '==', published); +} + +export function publishedGuestbookEntry(published = true): FirestoreQueryConstraint { return where('published', '==', published); } diff --git a/apps/demo-firebase/src/lib/guestbook/guestbook.ts b/apps/demo-firebase/src/lib/guestbook/guestbook.ts index a060b835f..f80237982 100644 --- a/apps/demo-firebase/src/lib/guestbook/guestbook.ts +++ b/apps/demo-firebase/src/lib/guestbook/guestbook.ts @@ -12,7 +12,7 @@ export interface Guestbook { * * If not active, this item is still considered locked. */ - active: boolean; + published?: boolean; /** * Guestbook name */ @@ -37,7 +37,7 @@ export const guestbookCollectionPath = 'guestbook'; export const guestbookConverter = makeSnapshotConverterFunctions({ fields: { - active: firestoreBoolean(), + published: firestoreBoolean(), name: firestoreString(), locked: firestoreBoolean({ default: false }), lockedAt: firestoreDate() @@ -87,7 +87,7 @@ export interface GuestbookEntryRef extends DocumentReferenceRef export class GuestbookEntryDocument extends AbstractFirestoreDocumentWithParent { } -export const guestbookEntryCollectionPath = 'guestbookEntry'; +export const guestbookCollectionGuestbookEntryCollectionPath = 'entry'; export const guestbookEntryConverter = makeSnapshotConverterFunctions({ fields: { @@ -101,7 +101,7 @@ export const guestbookEntryConverter = makeSnapshotConverterFunctions CollectionReference { return (guestbook: GuestbookDocument) => { - return context.subcollection(guestbook.documentRef, guestbookEntryCollectionPath).withConverter(guestbookEntryConverter); + return context.subcollection(guestbook.documentRef, guestbookCollectionGuestbookEntryCollectionPath).withConverter(guestbookEntryConverter); }; } diff --git a/apps/demo-firebase/src/lib/profile/profile.ts b/apps/demo-firebase/src/lib/profile/profile.ts index 671dbd784..42f30e944 100644 --- a/apps/demo-firebase/src/lib/profile/profile.ts +++ b/apps/demo-firebase/src/lib/profile/profile.ts @@ -66,7 +66,7 @@ export interface ProfilePrivateDataRef extends DocumentReferenceRef { } -export const profilePrivateDataCollectionPath = 'profilePrivateData'; +export const profileCollectionProfilePrivateDataCollectionPath = 'private'; export const profilePrivateDataIdentifier = '0'; export const profilePrivateDataConverter = makeSnapshotConverterFunctions({ @@ -78,7 +78,7 @@ export const profilePrivateDataConverter = makeSnapshotConverterFunctions CollectionReference { return (profile: ProfileDocument) => { - return context.subcollection(profile.documentRef, profilePrivateDataCollectionPath).withConverter(profilePrivateDataConverter); + return context.subcollection(profile.documentRef, profileCollectionProfilePrivateDataCollectionPath).withConverter(profilePrivateDataConverter); }; } diff --git a/apps/demo/src/app/modules/demo/modules/app/modules/guestbook/container/guestbook.view.component.html b/apps/demo/src/app/modules/demo/modules/app/modules/guestbook/container/guestbook.view.component.html index eb6e15856..f6c16ae82 100644 --- a/apps/demo/src/app/modules/demo/modules/app/modules/guestbook/container/guestbook.view.component.html +++ b/apps/demo/src/app/modules/demo/modules/app/modules/guestbook/container/guestbook.view.component.html @@ -7,6 +7,7 @@

{{ name$ | async }}

You have signed this guest book.

+

Your entry is not public.

diff --git a/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.collection.store.ts b/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.collection.store.ts index e7e9d1318..480b2fb05 100644 --- a/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.collection.store.ts +++ b/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.collection.store.ts @@ -1,12 +1,13 @@ import { Injectable } from "@angular/core"; import { AbstractDbxFirebaseCollectionStore } from "@dereekb/dbx-firebase"; -import { DemoFirestoreCollections, Guestbook, GuestbookDocument } from "@dereekb/demo-firebase"; +import { DemoFirestoreCollections, Guestbook, GuestbookDocument, publishedGuestbook } from "@dereekb/demo-firebase"; @Injectable() export class GuestbookCollectionStore extends AbstractDbxFirebaseCollectionStore { constructor(collections: DemoFirestoreCollections) { super({ firestoreCollection: collections.guestbookFirestoreCollection }); + this.setConstraints(publishedGuestbook()); // todo: replace with filter } } diff --git a/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.collection.store.ts b/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.collection.store.ts index 831cb98ff..227073bfd 100644 --- a/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.collection.store.ts +++ b/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.collection.store.ts @@ -1,6 +1,6 @@ import { Optional, Injectable } from "@angular/core"; import { AbstractDbxFirebaseCollectionWithParentStore } from "@dereekb/dbx-firebase"; -import { DemoFirestoreCollections, Guestbook, GuestbookDocument, GuestbookEntry, GuestbookEntryDocument } from "@dereekb/demo-firebase"; +import { DemoFirestoreCollections, Guestbook, GuestbookDocument, GuestbookEntry, GuestbookEntryDocument, publishedGuestbookEntry } from "@dereekb/demo-firebase"; import { GuestbookDocumentStore } from "./guestbook.document.store"; @Injectable() @@ -8,6 +8,7 @@ export class GuestbookEntryCollectionStore extends AbstractDbxFirebaseCollection constructor(collections: DemoFirestoreCollections, @Optional() parent: GuestbookDocumentStore) { super({ collectionFactory: collections.guestbookEntryCollectionFactory }); + this.setConstraints(publishedGuestbookEntry()); // todo: replace with filter if (parent) { this.setParentStore(parent); diff --git a/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.document.store.directive.ts b/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.document.store.directive.ts index 9e5e329c5..5fa7d6228 100644 --- a/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.document.store.directive.ts +++ b/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.document.store.directive.ts @@ -1,6 +1,7 @@ import { Directive } from "@angular/core"; import { DbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreDirective } from "@dereekb/dbx-firebase"; import { GuestbookEntry, GuestbookEntryDocument } from "@dereekb/demo-firebase"; +import { map } from "rxjs"; import { GuestbookEntryDocumentStore } from "./guestbook.entry.document.store"; @Directive({ @@ -14,4 +15,6 @@ export class DemoGuestbookEntryDocumentStoreDirective extends DbxFirebaseDocumen super(store); } + readonly unpublished$ = this.data$.pipe(map((x) => !x.published)); + } diff --git a/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.document.store.ts b/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.document.store.ts index aa1cbfc83..6761644c3 100644 --- a/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.document.store.ts +++ b/apps/demo/src/app/modules/demo/modules/shared/modules/guestbook/store/guestbook.entry.document.store.ts @@ -1,4 +1,4 @@ -import { first, Observable, shareReplay, from, switchMap } from 'rxjs'; +import { first, Observable, shareReplay, from, switchMap, map } from 'rxjs'; import { Optional, Injectable } from "@angular/core"; import { LoadingState, loadingStateFromObs } from '@dereekb/rxjs'; import { AbstractDbxFirebaseDocumentWithParentStore } from "@dereekb/dbx-firebase"; diff --git a/apps/demo/src/app/modules/landing/container/layout.component.html b/apps/demo/src/app/modules/landing/container/layout.component.html index 3a521ffaa..d17c1db8e 100644 --- a/apps/demo/src/app/modules/landing/container/layout.component.html +++ b/apps/demo/src/app/modules/landing/container/layout.component.html @@ -12,7 +12,25 @@

DbxComponents

- + + +
+

+ +

+
+ + + +
@@ -39,7 +57,7 @@

{{ package.name }}

Primary Packages

- + , @@ -52,7 +70,7 @@

{{ package.name }}

- + , diff --git a/apps/demo/src/app/modules/landing/container/layout.component.ts b/apps/demo/src/app/modules/landing/container/layout.component.ts index ddb6a6ac9..4ea4bee08 100644 --- a/apps/demo/src/app/modules/landing/container/layout.component.ts +++ b/apps/demo/src/app/modules/landing/container/layout.component.ts @@ -1,4 +1,4 @@ -import { ClickableAnchor, ClickableAnchorLink, ClickableIconAnchorLink } from '@dereekb/dbx-core'; +import { ClickableAnchorLink } from '@dereekb/dbx-core'; import { Component } from '@angular/core'; import packageInfo from '../../../../../../../package.json'; @@ -24,7 +24,20 @@ export class LandingLayoutComponent { ref: 'demo' }; + readonly circleciAnchor: ClickableAnchorLink = { + title: 'CircleCI', + url: 'https://circleci.com/gh/dereekb/dbx-components/tree/main' + }; + readonly packages: LandingItem[] = [{ + name: '@dereekb/dbx-form', + description: 'Forms extension for @dereekb/dbx-web to make composing and consuming form easy.', + packages: [{ + title: '@ngx-formly/schematics', + url: 'https://formly.dev/', + target: '_blank' + }] + }, { name: '@dereekb/dbx-web', description: 'Full set of components for Angular in the browser. Built on top of @angular/material.', packages: [{ @@ -33,24 +46,28 @@ export class LandingLayoutComponent { target: '_blank' }] }, { - name: '@dereekb/dbx-form', - description: 'Forms extension for @dereekb/dbx-web to make composing and consuming form easy.', + name: '@dereekb/dbx-core', + description: 'Set of directives and utilities for any Angular project.', packages: [{ - title: '@ngx-formly/schematics', - url: 'https://formly.dev/', + title: 'Angular', + url: 'https://angular.io/', target: '_blank' }] }, { - name: '@dereekb/dbx-core', - description: 'Set of directives and utilities for Angular.', + name: '@dereekb/firebase-server', + description: 'Extension of @dereekb/firebase for firebase server projects. Provides patterns and tooling for using nestjs in Firebase.', packages: [{ - title: 'Angular', - url: 'https://angular.io/', + title: 'firebase', + url: 'https://firebase.google.com/', + target: '_blank' + }, { + title: 'nestjs', + url: 'https://nestjs.com/', target: '_blank' }] }, { name: '@dereekb/firebase', - description: 'Set of firebase utilities for the firebase for the web.', + description: 'Set of firebase patterns for the firebase for the web.', packages: [{ title: 'firebase', url: 'https://firebase.google.com/', @@ -70,7 +87,7 @@ export class LandingLayoutComponent { }] }, { name: '@dereekb/rxjs', - description: 'Set of rxjs utilities, including loading states and iterators.', + description: 'Set of rxjs utilities, including filters, loading states, rxjs operators, and async iterators.', packages: [{ title: 'rxjs', url: 'https://rxjs.dev/', @@ -80,9 +97,21 @@ export class LandingLayoutComponent { url: 'https://ngrx.io/', target: '_blank' }] + }, { + name: '@dereekb/model', + description: 'Utilities for dealing with models and extensions for the class-transformer and class-validator packages.', + packages: [{ + title: 'class-transformer', + url: 'https://github.com/typestack/class-transformer', + target: '_blank' + }, { + title: 'class-validator', + url: 'https://github.com/typestack/class-validator', + target: '_blank' + }] }, { name: '@dereekb/util', - description: 'Set of general utilities, consumed by other @dereekb packages.', + description: 'Set of general utilities, data models and patterns that are consumed by other @dereekb packages.', packages: [] }, { name: '@dereekb/browser', diff --git a/apps/demo/src/app/modules/landing/landing.scss b/apps/demo/src/app/modules/landing/landing.scss index 79afe307f..1c3ce0387 100644 --- a/apps/demo/src/app/modules/landing/landing.scss +++ b/apps/demo/src/app/modules/landing/landing.scss @@ -31,3 +31,42 @@ } .features {} + +.star-on-github-widget { + // https://buttons.github.io/ + + display: inline-block; + overflow: hidden; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; + font-size: 0; + line-height: 0; + white-space: nowrap; + + .star-on-github { + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; + text-decoration: none; + outline: 0; + color: #24292f; + background-color: #ebf0f4; + border-color: rgba(27, 31, 36, .15); + background-image: linear-gradient(180deg, #f6f8fa, #ebf0f4 90%); + + border-radius: 0.25em; + + position: relative; + display: inline-flex; + height: 14px; + padding: 2px 5px; + font-size: 11px; + font-weight: 600; + line-height: 14px; + vertical-align: bottom; + cursor: pointer; + user-select: none; + background-repeat: repeat-x; + background-position: -1px -1px; + background-size: 110% 110%; + border: 1px solid; + } + +} diff --git a/firestore.rules b/firestore.rules index c3c1733dc..fd49e0509 100644 --- a/firestore.rules +++ b/firestore.rules @@ -1,8 +1,31 @@ rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { - match /{document=**} { - allow read, write: if true; + + match /profile/{profile} { + allow read: if resourceIsOwnedByAuthUserId(); } + + match /guestbook/{guestbook} { + allow read: if resourceIsPublished(); + + match /entry/{entry} { + + // Can read any entry that is owned or published. + allow get: if resourceIsPublished() || resourceIsOwnedByAuthUserId(); + + // Can only query if the guestbook entry is published. + allow list: if resourceIsPublished(); + } + } + + function resourceIsPublished() { + return (resource.data.published != false); + } + + function resourceIsOwnedByAuthUserId() { + return (resource.id == request.auth.uid); + } + } } diff --git a/packages/dbx-web/src/lib/layout/style/_style.scss b/packages/dbx-web/src/lib/layout/style/_style.scss index 164f27de0..0ebe2f526 100644 --- a/packages/dbx-web/src/lib/layout/style/_style.scss +++ b/packages/dbx-web/src/lib/layout/style/_style.scss @@ -22,7 +22,9 @@ padding: 0 !important; } - @each $i, $padding in theming.$padding-map { + @each $i, + $padding in theming.$padding-map { + .pad-#{$i}, .padding-#{$i} { padding: $padding; @@ -37,6 +39,15 @@ display: inline; } + .d-iflex { + display: inline-flex; + } + + // force + .d-fiflex { + display: inline-flex !important; + } + } @mixin color($theme-config) {