vte.cx ユーザー作成グループを作成する

# はじめに
ユーザーフォルダ作成がうまく理解できなかったので
簡単な構成のデモアプリを作成しました。

[公式ドキュメント](https://vte.cx/documentation.html)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660329/68f0f86b-ed57-ed16-54be-eeef5a05bfc4.png)

# ユーザー作成グループとは

ユーザー作成グループとはユーザーが自由に作れるグループのことです。
例えば、ユーザーの下に`company_123`というグループを作って、他のユーザーをそこに所属させることができます。

ここではcompanyに所属させる人を`「親」`、所属させられる人を`「子」`として表現します。

またこの`company`というグループに属する際に`署名`というものが必要になります。

この署名は`親`から`子`に送ってグループに入ってもらう事もできますし、`子`から`親`に送って入る事もできます。

### では説明です。
以下は親から子に所属依頼をする流れ

![](https://3.bp.blogspot.com/-W5mGOvhdhhQ/VdL1NTw8xTI/AAAAAAAAw7k/RHAphiMFYZc/s400/mensetsu_hitori_man.png)

1.グループの作成(親のみ)
2.エントリーを登録(親or子)
3.親の署名
4.子の署名
5.グループに子が所属される

子から親に所属依頼をする時には1が不要になり、3と4が入れ替わります。

#### 1.グループの作成

ここでは`company_${uid}`という親ユーザーのuidを使ってグループを作成します。

server/create-own-company.tsx

```tsx
import * as vtecxapi from 'vtecxapi'

const uid = vtecxapi.uid()

const postData: VtecxApp.Entry[] = []

const req = {
  title: String(uid),
  link: [
    {
      ___href: `/_user/${uid}/company_${uid}`,
      ___rel: 'self'
// ___hrefに/_user/親id/会社idとしてここで会社を作成しています。
    }
  ]
}

postData.push(req)

if(postData && postData.length) {
  vtecxapi.put(postData)
} else {
  vtecxapi.sendError(400,'No Request Data')
}
```

上記のサービスを実行後

server/get-info.tsx

```tsx
import * as vtecxapi from 'vtecxapi'

const users = vtecxapi.getFeed('/_user/21749')
```

でFeed情報をみると
以下のように21749というidのユーザーの下にグループが作成されているのを確認できます。

```json
{
  "author": [
    {
      "uri": "urn:vte.cx:created:21749"
    }
  ],
  "id": "/_user/21749/company_21749,1",
  "link": [
    {
      "___href": "/_user/21749/company_21749",
      "___rel": "self"
    }
  ],
  "published": "2021-02-02T13:56:21.650+09:00",
  "title": "21749",
  "updated": "2021-02-02T13:56:21.650+09:00"
}
```

親はこの`/_user/21749/company_21749`に子を所属させます。

#### 2.エントリーを登録

ここでは署名をする際の下準備をしていきます。
以下のファイルではurlにchildUidが指定された場合(親から子)とparentUidが指定された場合(子から親)で処理を分けています。

server/submit-entry-before-signature.tsx

```tsx
import * as vtecxapi from 'vtecxapi'

const uid = vtecxapi.uid()

const childUid = vtecxapi.getQueryString('childUid')

const parentUid = vtecxapi.getQueryString('parentUid')

// * エントリーを登録
// * key:/_user/親id/group名/子id
// _userというシステムグループの中の123というidのユーザーのmygroupといいうグループの下に456というユーザーがいる。
// * alias:/_user/子id/group/group名
// _userというシステムグループの中の456というidのユーザーはmygroupというグループに所属している。

const postData: any = []

// * 親が子に参加依頼する分岐
if (childUid && childUid.length) {
  const companyCode = 'company_' + uid
  const key = `/_user/${uid}/${companyCode}/${childUid}`
  const alias = `/_user/${childUid}/group/${companyCode}`

  const req: VtecxApp.Entry = {
    link: [
      {
        ___href: key,
        ___rel: 'self'
      },
      {
        ___href: alias,
        ___rel: 'alternate'
      }
    ]
  }

  postData.push(req)
  if (postData.length && childUid) {
    vtecxapi.put(postData)
  }

// * 子がそのグループに参加申請する分岐
} else if (parentUid && parentUid.length) {
  const companyCode = 'company_' + parentUid
  const key = `/_user/${parentUid}/${companyCode}/${uid}`
  const alias = `/_user/${uid}/group/${companyCode}`

  const req: VtecxApp.Entry = {
    link: [
      {
        ___href: key,
        ___rel: 'self'
      },
      {
        ___href: alias,
        ___rel: 'alternate'
      }
    ]
  }

  postData.push(req)
  if (postData.length && parentUid) {
    vtecxapi.put(postData)
  }
} else if (childUid && childUid.length && parentUid && parentUid.length) {
  vtecxapi.sendError(400, '親と子のuidがどちらも指定されています')
} else {
  vtecxapi.sendError(400, '値が不正です')
}

```

親から子,子から親への署名をする際に必要な処理で、以下のaliasがとても重要な役割を果たします。

```tsx
const alias = `/_user/${childUid}/group/${companyCode}`
```

このaliasを使って後述する署名を行います。
このaliasが親と子の間の架け橋になります。

#### 3.親の署名

まさに中学生の頃歴史の時間に習った勘合貿易のようなイメージです。

> それぞれ割ったお札を持ちます。
持っている札の片割れと、相手が持っている片割れを合体させてニセモノかどうかを判別します。

![](https://3.bp.blogspot.com/-R3wLo3CaC10/VuKD24dQk8I/AAAAAAAA4wE/liqwPwnvxE8-UQoxh9izHN0dleyd67OsQ/s800/kangoufu.png)

親が作成したエントリー(alias)を参照して署名します。

ここでのaliasは先ほど作成した

```tsx
const alias = `/_user/${childUid}/group/${companyCode}`
```

こちらです。

署名の方法は以下です。

```
PUT {key}?_signature&_revision={リビジョン(任意)}
```

ここでの`{key}`は先ほどのaliasに設定した`/_user/${childUid}/group/${companyCode}`になります。

```tsx
 const handleSubmitSignatureByParent = async () => {
    try {
      axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'
      await axios.get(
        '/s/submit-entry-before-signature',
        { params: { childUid: childUid } }
      )
      const getUid = await axios.get(
        '/d/?_uid'
      )
      const uid = getUid.data.feed.title
      const companyCode = 'company_' + uid
      await axios.put(`/d/_user/${uid}/${companyCode}/${childUid}?_signature&_revision=1`)
    } catch (e) {
      alert(e.message)
    }
    setChildUid('')
  }
```

#### 4.子の署名

子の署名は先ほどのaliasを使います。


```tsx
const handleSubmitSignatureByChild = async () => {
    const getUid = await axios.get(
      '/d/?_uid'
    )

    const uid = getUid.data.feed.title
    const companyCode = 'company_' + parentUid

    try {
      axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'
      await axios.get(
        '/s/submit-entry-before-signature',
        { params: { parentUid: parentUid } }
      )
      axios.put(`/d/_user/${uid}/group/${companyCode}?_signature&_revision=1`)
    } catch (e) {
      alert(e.message)
    }

    setParentUid('')
  }
```

#### 5.グループに子が所属される

子が署名をした段階でフレームワーク側で署名検証が行われ、成功した場合、グループに所属することができます。

server/get-info.tsx

```tsx
import * as vtecxapi from 'vtecxapi'

const users = vtecxapi.getFeed('/_user/21749/company_21749')
```

でFeed情報をみると


```json
{
  "author": [
    {
      "uri": "urn:vte.cx:created:21749"
    },
    {
      "uri": "urn:vte.cx:updated:21750"
    }
  ],
  "id": "/_user/21749/company_21749/21750,4",
  "link": [
    {
      "___href": "/_user/21749/company_21749/21750",
      "___rel": "self",
      "___title": "1,21749,HjXN6XbOkbKL2yunmXaGJ+x+gLjAPj4jrAl3SKToZdY="
    },
    {
      "___href": "/_user/21750/group/company_21749",
      "___rel": "alternate",
      "___title": "3,21750,UHiBErXwriNKwf6ddBhFbHqJc2TFkPDWbPBZyneMSVA="
    }
  ],
  "published": "2021-02-02T14:10:41.356+09:00",
  "updated": "2021-02-02T14:11:34.602+09:00"
},
```

この中のlinkを見てみると署名をする前に行った下準備がlinkとして格納されています。

```json
___href: "/_user/21749/company_21749/21750"
___href: "/_user/21750/group/company_21749"
```

これで
21749というユーザーの下にあるcompany_21749という会社に21750というユーザーが所属されていることが確認できました。

![](https://3.bp.blogspot.com/-IXeMg300nUk/VY4Wz8dS6YI/AAAAAAAAut8/n7V-CA0HCPQ/s400/syainsyou_man.png)