Skip to content

Commit

Permalink
Create alias contracts in frontend in create-daml-app
Browse files Browse the repository at this point in the history
Creating them in the setup script is nice but it makes it much harder
to port this to Daml hub where we cannot rely on this.

This also requires figuring out the public party in the frontend.

I’ve chosen to infer it from the user rights which seems broadly
sensible.

For the backwards compat mode, I just hardcoded it because there isn’t
a great way to figure it out.

changelog_begin
changelog_end
  • Loading branch information
cocreature committed Feb 10, 2022
1 parent d2f6224 commit fe5b8d4
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 8 deletions.
5 changes: 1 addition & 4 deletions templates/create-daml-app/daml/Setup.daml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import DA.Optional (fromSomeNote)
import qualified DA.Text as T
import Daml.Script

import User (Alias(..))

-- | A test user for the create-daml-app network.
data TestUser = TestUser with
alias : Text
Expand All @@ -24,7 +22,6 @@ createTestUser : TestUser -> Script Party
createTestUser TestUser{alias, public} = do
u <- getOrCreateUser alias (Some public)
let p = getPrimaryParty u
submit p $ createCmd $ Alias p alias public
pure p

-- | Create the public party.
Expand All @@ -44,7 +41,7 @@ getOrCreateUser alias publicM = do
UserNotFound _ -> do
p <- allocateParty alias
let u = User userId (Some p)
createUser u $ [CanActAs p] ++ [CanReadAs public | Some public <- [publicM]]
createUser u $ CanActAs p :: [CanReadAs public | Some public <- [publicM]]
pure u

-- | Convert a text to a valid user id.
Expand Down
1 change: 0 additions & 1 deletion templates/create-daml-app/daml/User.daml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ module User where
-- MAIN_TEMPLATE_BEGIN
template User with
username: Party
public: Party
following: [Party]
where
signatory username
Expand Down
1 change: 1 addition & 0 deletions templates/create-daml-app/ui/src/Credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { User } from "@daml/ledger";

export type Credentials = {
party: string;
publicParty: string;
token: string;
user: User;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ type Props = {
onLogin: (credentials: Credentials) => void;
}

const toAlias = (userId: string): string =>
userId.charAt(0).toUpperCase() + userId.slice(1);

/**
* React component for the login screen of the `App`.
*/
Expand All @@ -24,9 +27,13 @@ const LoginScreen: React.FC<Props> = ({onLogin}) => {
const ledger = new Ledger({token: credentials.token});
let userContract = await ledger.fetchByKey(User.User, credentials.party);
if (userContract === null) {
const user = {username: credentials.party, following: [], public: 'public'};
const user = {username: credentials.party, following: []};
userContract = await ledger.create(User.User, user);
}
let userAlias = await ledger.fetchByKey(User.Alias, {_1: credentials.party, _2: credentials.publicParty});
if (userAlias === null) {
await ledger.create(User.Alias, {username: credentials.party, alias: toAlias(credentials.user.userId), public: credentials.publicParty});
}
onLogin(credentials);
} catch(error) {
alert(`Unknown error:\n${JSON.stringify(error)}`);
Expand Down Expand Up @@ -72,8 +79,14 @@ const LoginScreen: React.FC<Props> = ({onLogin}) => {
alert(`Failed to login as '${username}':\n${errorMsg}`);
throw error;
});
const publicParty:string = await auth.userManagement.publicParty(username, ledger).catch((error) => {
const errorMsg = error instanceof Error ? error.toString() : JSON.stringify(error);
alert(`Failed to login as '${username}':\n${errorMsg}`);
throw error;
});
await login({user: {userId: username, primaryParty: primaryParty},
party: primaryParty,
publicParty: publicParty,
token: auth.makeToken(username)});
}

Expand All @@ -100,7 +113,8 @@ const LoginScreen: React.FC<Props> = ({onLogin}) => {
<DamlHubLoginBtn
onLogin={creds => {
if (creds) {
login({party:creds.party, user: {userId: creds.partyName, primaryParty: creds.party}, token:creds.token});
// TODO (MK) Fix public party in Daml hub
login({party:creds.party, publicParty: "FIXME", user: {userId: creds.partyName, primaryParty: creds.party}, token:creds.token});
}
}}
options={{
Expand All @@ -120,9 +134,11 @@ const LoginScreen: React.FC<Props> = ({onLogin}) => {
if (isLoading === false && isAuthenticated === true) {
if (user !== undefined) {
const party = user["https://daml.com/ledger-api"];
// TODO (MK) Fix public party with Auth0
const creds: Credentials = {
user: {userId: user.email ?? user.name ?? party, primaryParty: party},
party: party,
publicParty: "FIXME",
token: (await getAccessTokenSilently({
audience: "https://daml.com/ledger-api"}))};
login(creds);
Expand Down
17 changes: 16 additions & 1 deletion templates/create-daml-app/ui/src/config.ts.template
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

import { encode } from 'jwt-simple';
import { isRunningOnHub } from '@daml/hub-react';
import Ledger from '@daml/ledger';
import Ledger, { CanReadAs } from '@daml/ledger';

export type UserManagement = {
tokenPayload: (loginName: string, ledgerId: string) => Object,
primaryParty: (loginName: string, ledger: Ledger) => Promise<string>,
publicParty: (loginName: string, ledger: Ledger) => Promise<string>,
};

export type Insecure = {
Expand Down Expand Up @@ -39,6 +40,9 @@ export const noUserManagement: UserManagement = {
}
}),
primaryParty: async (loginName: string, ledger: Ledger) => loginName,
// Without user management, we force a specific party id here because
// we mainly care about this for vmbc and there we can support this.
publicParty: async (loginName: string, ledger: Ledger) => 'public',
};

// Used on SDK >= 2.0.0 with the exception of VMBC
Expand All @@ -56,6 +60,17 @@ export const withUserManagement: UserManagement = {
throw new Error(`User '${loginName}' has no primary party`);
}

},
publicParty: async (loginName, ledger: Ledger) => {
const rights = await ledger.listUserRights();
const readAsRights: CanReadAs[] = rights.filter((x) : x is CanReadAs => x.type === "CanReadAs");
if (readAsRights.length === 0) {
throw new Error(`User '${loginName} has no readAs claims for a public party`);
} else if (readAsRights.length > 1) {
throw new Error(`User '${loginName} has readAs claims for more than one party`);
} else {
return readAsRights[0].party;
}
}
};

Expand Down

0 comments on commit fe5b8d4

Please sign in to comment.