| @@ -0,0 +1,199 @@ | ||
| +package de.tutao.tutanota.push; | ||
| + | ||
| +import android.app.Notification; | ||
| +import android.app.NotificationManager; | ||
| +import android.app.Service; | ||
| +import android.content.Context; | ||
| +import android.content.Intent; | ||
| +import android.media.RingtoneManager; | ||
| +import android.net.Uri; | ||
| +import android.os.Handler; | ||
| +import android.os.IBinder; | ||
| +import android.os.Looper; | ||
| +import android.text.TextUtils; | ||
| +import android.util.Log; | ||
| + | ||
| +import org.json.JSONArray; | ||
| +import org.json.JSONException; | ||
| +import org.json.JSONObject; | ||
| + | ||
| +import java.io.BufferedInputStream; | ||
| +import java.io.BufferedReader; | ||
| +import java.io.IOException; | ||
| +import java.io.InputStream; | ||
| +import java.io.InputStreamReader; | ||
| +import java.io.OutputStream; | ||
| +import java.io.UnsupportedEncodingException; | ||
| +import java.net.HttpURLConnection; | ||
| +import java.net.URL; | ||
| +import java.net.URLEncoder; | ||
| +import java.nio.charset.Charset; | ||
| +import java.util.Base64; | ||
| +import java.util.Collections; | ||
| +import java.util.Random; | ||
| +import java.util.concurrent.TimeUnit; | ||
| +import java.util.concurrent.atomic.AtomicReference; | ||
| + | ||
| +import de.tutao.tutanota.BuildConfig; | ||
| +import de.tutao.tutanota.Crypto; | ||
| +import de.tutao.tutanota.R; | ||
| +import de.tutao.tutanota.Utils; | ||
| + | ||
| +public class PushNotificationService extends Service { | ||
| + | ||
| + private static final String TAG = "PushNotificationService"; | ||
| + | ||
| + private static final int NOTIFICATION_ID = 341; | ||
| + private final LooperThread looperThread = new LooperThread(this::connect); | ||
| + private final SseStorage sseStorage = new SseStorage(this); | ||
| + | ||
| + final AtomicReference<HttpURLConnection> httpsURLConnectionRef = new AtomicReference<>(null); | ||
| + private final Crypto crypto = new Crypto(this); | ||
| + private SseInfo connectedSseInfo; | ||
| + | ||
| + public PushNotificationService() { | ||
| + } | ||
| + | ||
| + @Override | ||
| + public IBinder onBind(Intent intent) { | ||
| + return null; | ||
| + } | ||
| + | ||
| + @Override | ||
| + public int onStartCommand(Intent intent, int flags, int startId) { | ||
| + Log.d(TAG, "Received start"); | ||
| + HttpURLConnection connection = httpsURLConnectionRef.get(); | ||
| + if (this.looperThread.isAlive()) { | ||
| + Log.d(TAG, "Reconnect onStartCommand"); | ||
| + if (connection != null && this.connectedSseInfo != null && !this.connectedSseInfo.equals(sseStorage.getSseInfo())) { | ||
| + connection.disconnect(); | ||
| + }else { | ||
| + this.looperThread.getHandler().post(this::connect); | ||
| + } | ||
| + } else { | ||
| + Log.d(TAG, "Starting looperThread"); | ||
| + looperThread.start(); | ||
| + } | ||
| + return Service.START_STICKY; | ||
| + } | ||
| + | ||
| + private void connect() { | ||
| + Log.d(TAG, "Starting SSE connection"); | ||
| + Random random = new Random(); | ||
| + BufferedReader reader = null; | ||
| + SseInfo sseInfo = sseStorage.getSseInfo(); | ||
| + if (sseInfo == null) { | ||
| + Log.d(TAG, "sse info not available skip reconnect"); | ||
| + return; | ||
| + } | ||
| + this.connectedSseInfo = sseInfo; | ||
| + try { | ||
| + URL url = new URL(sseInfo.getSseOrigin() + "/sse?_body=" + requestJson(sseInfo)); | ||
| + HttpURLConnection httpsURLConnection = (HttpURLConnection) url.openConnection(); | ||
| + this.httpsURLConnectionRef.set(httpsURLConnection); | ||
| + httpsURLConnection.setRequestProperty("Content-Type", "application/json"); | ||
| + httpsURLConnection.setRequestProperty("Connection", "Keep-Alive"); | ||
| + httpsURLConnection.setRequestProperty("Keep-Alive", "header"); | ||
| + httpsURLConnection.setRequestProperty("Connection", "close"); | ||
| + httpsURLConnection.setRequestProperty("Accept", "text/event-stream"); | ||
| + httpsURLConnection.setRequestMethod("GET"); | ||
| + //httpsURLConnection.setConnectTimeout(70000); | ||
| + httpsURLConnection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(15)); | ||
| + InputStream inputStream = new BufferedInputStream(httpsURLConnection.getInputStream()); | ||
| + reader = new BufferedReader(new InputStreamReader(inputStream)); | ||
| + String event; | ||
| + while ((event = reader.readLine()) != null) { | ||
| + if (!event.startsWith("data: ")) { | ||
| + continue; | ||
| + } | ||
| + event = event.substring(6); | ||
| + if (event.matches("^[0-9]{1,}$")) | ||
| + continue; | ||
| + | ||
| + NotificationManager notificationManager = | ||
| + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); | ||
| + | ||
| + Uri notificatoinUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); | ||
| + | ||
| + Notification notification = new Notification.Builder(this) | ||
| + .setContentTitle(event) | ||
| + .setSmallIcon(R.drawable.ic_status) | ||
| + .setSound(notificatoinUri) | ||
| + .setVibrate(new long[]{3000}) | ||
| + .build(); | ||
| + //noinspection ConstantConditions | ||
| + notificationManager.notify(NOTIFICATION_ID, notification); | ||
| + } | ||
| + } catch (Exception ignored) { | ||
| + HttpURLConnection httpURLConnection = httpsURLConnectionRef.get(); | ||
| + try { | ||
| + // we get not authorized for the stored identifier and user ids, so remove them | ||
| + if (httpURLConnection != null && httpURLConnection.getResponseCode() == 403) { | ||
| + Log.e(TAG, "not authorized to connect, disable reconnect"); | ||
| + sseStorage.clear(); | ||
| + return; | ||
| + } | ||
| + } catch (IOException e) { | ||
| + // ignore Exception when getting status code. | ||
| + } | ||
| + int delay = random.nextInt(15) + 15; | ||
| + Log.e(TAG, "error opening sse, rescheduling after " + delay, ignored); | ||
| + looperThread.getHandler().postDelayed(this::connect, | ||
| + TimeUnit.SECONDS.toMillis(delay)); | ||
| + } finally { | ||
| + if (reader != null) { | ||
| + try { | ||
| + reader.close(); | ||
| + } catch (IOException ignored) { | ||
| + } | ||
| + } | ||
| + } | ||
| + } | ||
| + | ||
| + private String requestJson(SseInfo sseInfo) { | ||
| + JSONObject jsonObject = new JSONObject(); | ||
| + try { | ||
| + jsonObject.put("_format", "0"); | ||
| + jsonObject.put("identifier", sseInfo.getPushIdentifier()); | ||
| + JSONArray jsonArray = new JSONArray(); | ||
| + for (String userId : sseInfo.getUserIds()) { | ||
| + JSONObject userIdObject = new JSONObject(); | ||
| + userIdObject.put("_id", generateId()); | ||
| + userIdObject.put("value", userId); | ||
| + jsonArray.put(userIdObject); | ||
| + } | ||
| + jsonObject.put("userIds", jsonArray); | ||
| + return URLEncoder.encode(jsonObject.toString(), "UTF-8"); | ||
| + } catch (JSONException | UnsupportedEncodingException e) { | ||
| + throw new RuntimeException(e); | ||
| + } | ||
| + } | ||
| + | ||
| + private String generateId() { | ||
| + byte[] bytes = new byte[4]; | ||
| + crypto.getRandomizer().nextBytes(bytes); | ||
| + return Utils.base64ToBase64Url(Utils.bytesToBase64(bytes)); | ||
| + } | ||
| +} | ||
| + | ||
| +class LooperThread extends Thread { | ||
| + | ||
| + private Handler handler; | ||
| + private Runnable initRunnable; | ||
| + | ||
| + LooperThread(Runnable initRunnable) { | ||
| + this.initRunnable = initRunnable; | ||
| + } | ||
| + | ||
| + @Override | ||
| + public void run() { | ||
| + Looper.prepare(); | ||
| + handler = new Handler(); | ||
| + handler.post(initRunnable); | ||
| + Looper.loop(); | ||
| + } | ||
| + | ||
| + public Handler getHandler() { | ||
| + return handler; | ||
| + } | ||
| +} |
| @@ -0,0 +1,120 @@ | ||
| +package de.tutao.tutanota.push; | ||
| + | ||
| +import android.content.Context; | ||
| +import android.content.SharedPreferences; | ||
| +import android.preference.PreferenceManager; | ||
| +import android.support.annotation.Nullable; | ||
| +import android.util.Log; | ||
| + | ||
| +import org.json.JSONArray; | ||
| +import org.json.JSONException; | ||
| +import org.json.JSONObject; | ||
| + | ||
| +import java.io.ByteArrayOutputStream; | ||
| +import java.util.ArrayList; | ||
| +import java.util.Collections; | ||
| +import java.util.HashMap; | ||
| +import java.util.List; | ||
| + | ||
| +public final class SseStorage { | ||
| + public static final String PUSH_IDENTIFIER_JSON_KEY = "pushIdentifier"; | ||
| + public static final String USER_IDS_JSON_KEY = "userIds"; | ||
| + public static final String SSE_ORIGIN_JSON_KEY = "sseOrigin"; | ||
| + | ||
| + private static final String SSE_INFO_PREF = "sseInfo"; | ||
| + private static final String TAG = SseStorage.class.getSimpleName(); | ||
| + | ||
| + | ||
| + private Context context; | ||
| + | ||
| + public SseStorage(Context context) { | ||
| + this.context = context; | ||
| + } | ||
| + | ||
| + @Nullable | ||
| + public String getPushIdentifier() { | ||
| + SseInfo sseInfo = getSseInfo(); | ||
| + if (sseInfo != null) { | ||
| + return sseInfo.getPushIdentifier(); | ||
| + } | ||
| + return null; | ||
| + } | ||
| + | ||
| + @Nullable | ||
| + public SseInfo getSseInfo() { | ||
| + String pushIdentifierPref = getPrefs().getString(SSE_INFO_PREF, null); | ||
| + if (pushIdentifierPref == null) { | ||
| + return null; | ||
| + } | ||
| + try { | ||
| + JSONObject jsonObject = new JSONObject(pushIdentifierPref); | ||
| + String identifier = jsonObject.getString(PUSH_IDENTIFIER_JSON_KEY); | ||
| + JSONArray userIdsArray = jsonObject.getJSONArray(USER_IDS_JSON_KEY); | ||
| + List<String> userIds = new ArrayList<>(userIdsArray.length()); | ||
| + for (int i = 0; i < userIdsArray.length(); i++) { | ||
| + userIds.add(userIdsArray.getString(i)); | ||
| + } | ||
| + String sseOrigin = jsonObject.getString(SSE_ORIGIN_JSON_KEY); | ||
| + return new SseInfo(identifier, userIds, sseOrigin); | ||
| + } catch ( JSONException e) { | ||
| + Log.w(TAG, "could read sse info", e); | ||
| + return null; | ||
| + } | ||
| + } | ||
| + | ||
| + public void storePushIdentifier(String identifier, String userId, String sseOrigin) { | ||
| + final SseInfo sseInfo = getSseInfo(); | ||
| + SseInfo newInfo; | ||
| + if (sseInfo == null) { | ||
| + newInfo = new SseInfo(identifier, Collections.singletonList(userId), sseOrigin); | ||
| + } else { | ||
| + List<String> userList = new ArrayList<>(sseInfo.getUserIds()); | ||
| + if (!userList.contains(userId)) { | ||
| + userList.add(userId); | ||
| + } | ||
| + newInfo = new SseInfo(identifier, userList, sseOrigin); | ||
| + } | ||
| + getPrefs().edit().putString(SSE_INFO_PREF, newInfo.toJSON()).apply(); | ||
| + } | ||
| + | ||
| + public void clear() { | ||
| + this.getPrefs().edit().clear().apply(); | ||
| + } | ||
| + | ||
| + private SharedPreferences getPrefs() { | ||
| + return PreferenceManager.getDefaultSharedPreferences(context); | ||
| + } | ||
| +} | ||
| + | ||
| +final class SseInfo { | ||
| + final private String pushIdentifier; | ||
| + final private List<String> userIds; | ||
| + final private String sseOrigin; | ||
| + | ||
| + SseInfo(String pushIdentifier, List<String> userIds, String sseOrigin) { | ||
| + this.pushIdentifier = pushIdentifier; | ||
| + this.userIds = userIds; | ||
| + this.sseOrigin = sseOrigin; | ||
| + } | ||
| + | ||
| + public String getPushIdentifier() { | ||
| + return pushIdentifier; | ||
| + } | ||
| + | ||
| + public List<String> getUserIds() { | ||
| + return userIds; | ||
| + } | ||
| + | ||
| + public String getSseOrigin() { | ||
| + return sseOrigin; | ||
| + } | ||
| + | ||
| + public String toJSON() { | ||
| + HashMap<String, Object> sseInfoMap = new HashMap<>(); | ||
| + sseInfoMap.put(SseStorage.PUSH_IDENTIFIER_JSON_KEY, this.pushIdentifier); | ||
| + sseInfoMap.put(SseStorage.USER_IDS_JSON_KEY, this.userIds); | ||
| + sseInfoMap.put(SseStorage.SSE_ORIGIN_JSON_KEY, this.sseOrigin); | ||
| + JSONObject jsonObject = new JSONObject(sseInfoMap); | ||
| + return jsonObject.toString(); | ||
| + } | ||
| +} |
| @@ -0,0 +1,40 @@ | ||
| +// @flow | ||
| +import {create, TypeRef} from "../../common/EntityFunctions" | ||
| + | ||
| +export const GeneratedIdWrapperTypeRef: TypeRef<GeneratedIdWrapper> = new TypeRef("sys", "GeneratedIdWrapper") | ||
| +export const _TypeModel: TypeModel = { | ||
| + "name": "GeneratedIdWrapper", | ||
| + "since": 32, | ||
| + "type": "AGGREGATED_TYPE", | ||
| + "id": 1349, | ||
| + "rootId": "A3N5cwAFRQ", | ||
| + "versioned": false, | ||
| + "encrypted": false, | ||
| + "values": { | ||
| + "_id": { | ||
| + "name": "_id", | ||
| + "id": 1350, | ||
| + "since": 32, | ||
| + "type": "CustomId", | ||
| + "cardinality": "One", | ||
| + "final": true, | ||
| + "encrypted": false | ||
| + }, | ||
| + "value": { | ||
| + "name": "value", | ||
| + "id": 1351, | ||
| + "since": 32, | ||
| + "type": "GeneratedId", | ||
| + "cardinality": "One", | ||
| + "final": false, | ||
| + "encrypted": false | ||
| + } | ||
| + }, | ||
| + "associations": {}, | ||
| + "app": "sys", | ||
| + "version": "32" | ||
| +} | ||
| + | ||
| +export function createGeneratedIdWrapper(): GeneratedIdWrapper { | ||
| + return create(_TypeModel) | ||
| +} |
| @@ -1,10 +1,115 @@ | ||
| // @flow | ||
| - | ||
| import {create, TypeRef} from "../../common/EntityFunctions" | ||
| -export const OrderProcessingAgreementTypeRef:TypeRef<OrderProcessingAgreement> = new TypeRef("sys", "OrderProcessingAgreement") | ||
| -export const _TypeModel:TypeModel= {"name":"OrderProcessingAgreement","since":31,"type":"LIST_ELEMENT_TYPE","id":1326,"rootId":"A3N5cwAFLg","versioned":false,"encrypted":true,"values":{"_format":{"name":"_format","id":1330,"since":31,"type":"Number","cardinality":"One","final":false,"encrypted":false},"_id":{"name":"_id","id":1328,"since":31,"type":"GeneratedId","cardinality":"One","final":true,"encrypted":false},"_ownerEncSessionKey":{"name":"_ownerEncSessionKey","id":1332,"since":31,"type":"Bytes","cardinality":"ZeroOrOne","final":true,"encrypted":false},"_ownerGroup":{"name":"_ownerGroup","id":1331,"since":31,"type":"GeneratedId","cardinality":"ZeroOrOne","final":true,"encrypted":false},"_permissions":{"name":"_permissions","id":1329,"since":31,"type":"GeneratedId","cardinality":"One","final":true,"encrypted":false},"customerAddress":{"name":"customerAddress","id":1334,"since":31,"type":"String","cardinality":"One","final":false,"encrypted":true},"signatureDate":{"name":"signatureDate","id":1335,"since":31,"type":"Date","cardinality":"One","final":false,"encrypted":false},"version":{"name":"version","id":1333,"since":31,"type":"String","cardinality":"One","final":false,"encrypted":false}},"associations":{"customer":{"name":"customer","id":1337,"since":31,"type":"ELEMENT_ASSOCIATION","cardinality":"One","refType":"Customer","final":true,"external":false},"signerUserGroupInfo":{"name":"signerUserGroupInfo","id":1336,"since":31,"type":"LIST_ELEMENT_ASSOCIATION","cardinality":"One","refType":"GroupInfo","final":false,"external":false}},"app":"sys","version":"31"} | ||
| +export const OrderProcessingAgreementTypeRef: TypeRef<OrderProcessingAgreement> = new TypeRef("sys", "OrderProcessingAgreement") | ||
| +export const _TypeModel: TypeModel = { | ||
| + "name": "OrderProcessingAgreement", | ||
| + "since": 31, | ||
| + "type": "LIST_ELEMENT_TYPE", | ||
| + "id": 1326, | ||
| + "rootId": "A3N5cwAFLg", | ||
| + "versioned": false, | ||
| + "encrypted": true, | ||
| + "values": { | ||
| + "_format": { | ||
| + "name": "_format", | ||
| + "id": 1330, | ||
| + "since": 31, | ||
| + "type": "Number", | ||
| + "cardinality": "One", | ||
| + "final": false, | ||
| + "encrypted": false | ||
| + }, | ||
| + "_id": { | ||
| + "name": "_id", | ||
| + "id": 1328, | ||
| + "since": 31, | ||
| + "type": "GeneratedId", | ||
| + "cardinality": "One", | ||
| + "final": true, | ||
| + "encrypted": false | ||
| + }, | ||
| + "_ownerEncSessionKey": { | ||
| + "name": "_ownerEncSessionKey", | ||
| + "id": 1332, | ||
| + "since": 31, | ||
| + "type": "Bytes", | ||
| + "cardinality": "ZeroOrOne", | ||
| + "final": true, | ||
| + "encrypted": false | ||
| + }, | ||
| + "_ownerGroup": { | ||
| + "name": "_ownerGroup", | ||
| + "id": 1331, | ||
| + "since": 31, | ||
| + "type": "GeneratedId", | ||
| + "cardinality": "ZeroOrOne", | ||
| + "final": true, | ||
| + "encrypted": false | ||
| + }, | ||
| + "_permissions": { | ||
| + "name": "_permissions", | ||
| + "id": 1329, | ||
| + "since": 31, | ||
| + "type": "GeneratedId", | ||
| + "cardinality": "One", | ||
| + "final": true, | ||
| + "encrypted": false | ||
| + }, | ||
| + "customerAddress": { | ||
| + "name": "customerAddress", | ||
| + "id": 1334, | ||
| + "since": 31, | ||
| + "type": "String", | ||
| + "cardinality": "One", | ||
| + "final": false, | ||
| + "encrypted": true | ||
| + }, | ||
| + "signatureDate": { | ||
| + "name": "signatureDate", | ||
| + "id": 1335, | ||
| + "since": 31, | ||
| + "type": "Date", | ||
| + "cardinality": "One", | ||
| + "final": false, | ||
| + "encrypted": false | ||
| + }, | ||
| + "version": { | ||
| + "name": "version", | ||
| + "id": 1333, | ||
| + "since": 31, | ||
| + "type": "String", | ||
| + "cardinality": "One", | ||
| + "final": false, | ||
| + "encrypted": false | ||
| + } | ||
| + }, | ||
| + "associations": { | ||
| + "customer": { | ||
| + "name": "customer", | ||
| + "id": 1337, | ||
| + "since": 31, | ||
| + "type": "ELEMENT_ASSOCIATION", | ||
| + "cardinality": "One", | ||
| + "refType": "Customer", | ||
| + "final": true, | ||
| + "external": false | ||
| + }, | ||
| + "signerUserGroupInfo": { | ||
| + "name": "signerUserGroupInfo", | ||
| + "id": 1336, | ||
| + "since": 31, | ||
| + "type": "LIST_ELEMENT_ASSOCIATION", | ||
| + "cardinality": "One", | ||
| + "refType": "GroupInfo", | ||
| + "final": false, | ||
| + "external": false | ||
| + } | ||
| + }, | ||
| + "app": "sys", | ||
| + "version": "32" | ||
| +} | ||
| -export function createOrderProcessingAgreement():OrderProcessingAgreement { | ||
| - return create(_TypeModel) | ||
| +export function createOrderProcessingAgreement(): OrderProcessingAgreement { | ||
| + return create(_TypeModel) | ||
| } |
| @@ -1,10 +1,42 @@ | ||
| // @flow | ||
| - | ||
| import {create, TypeRef} from "../../common/EntityFunctions" | ||
| -export const OrderProcessingAgreementsTypeRef:TypeRef<OrderProcessingAgreements> = new TypeRef("sys", "OrderProcessingAgreements") | ||
| -export const _TypeModel:TypeModel= {"name":"OrderProcessingAgreements","since":31,"type":"AGGREGATED_TYPE","id":1338,"rootId":"A3N5cwAFOg","versioned":false,"encrypted":false,"values":{"_id":{"name":"_id","id":1339,"since":31,"type":"CustomId","cardinality":"One","final":true,"encrypted":false}},"associations":{"agreements":{"name":"agreements","id":1340,"since":31,"type":"LIST_ASSOCIATION","cardinality":"One","refType":"OrderProcessingAgreement","final":true,"external":false}},"app":"sys","version":"31"} | ||
| +export const OrderProcessingAgreementsTypeRef: TypeRef<OrderProcessingAgreements> = new TypeRef("sys", "OrderProcessingAgreements") | ||
| +export const _TypeModel: TypeModel = { | ||
| + "name": "OrderProcessingAgreements", | ||
| + "since": 31, | ||
| + "type": "AGGREGATED_TYPE", | ||
| + "id": 1338, | ||
| + "rootId": "A3N5cwAFOg", | ||
| + "versioned": false, | ||
| + "encrypted": false, | ||
| + "values": { | ||
| + "_id": { | ||
| + "name": "_id", | ||
| + "id": 1339, | ||
| + "since": 31, | ||
| + "type": "CustomId", | ||
| + "cardinality": "One", | ||
| + "final": true, | ||
| + "encrypted": false | ||
| + } | ||
| + }, | ||
| + "associations": { | ||
| + "agreements": { | ||
| + "name": "agreements", | ||
| + "id": 1340, | ||
| + "since": 31, | ||
| + "type": "LIST_ASSOCIATION", | ||
| + "cardinality": "One", | ||
| + "refType": "OrderProcessingAgreement", | ||
| + "final": true, | ||
| + "external": false | ||
| + } | ||
| + }, | ||
| + "app": "sys", | ||
| + "version": "32" | ||
| +} | ||
| -export function createOrderProcessingAgreements():OrderProcessingAgreements { | ||
| - return create(_TypeModel) | ||
| +export function createOrderProcessingAgreements(): OrderProcessingAgreements { | ||
| + return create(_TypeModel) | ||
| } |
| @@ -1,10 +1,49 @@ | ||
| // @flow | ||
| - | ||
| import {create, TypeRef} from "../../common/EntityFunctions" | ||
| -export const SignOrderProcessingAgreementDataTypeRef:TypeRef<SignOrderProcessingAgreementData> = new TypeRef("sys", "SignOrderProcessingAgreementData") | ||
| -export const _TypeModel:TypeModel= {"name":"SignOrderProcessingAgreementData","since":31,"type":"DATA_TRANSFER_TYPE","id":1342,"rootId":"A3N5cwAFPg","versioned":false,"encrypted":false,"values":{"_format":{"name":"_format","id":1343,"since":31,"type":"Number","cardinality":"One","final":false,"encrypted":false},"customerAddress":{"name":"customerAddress","id":1345,"since":31,"type":"String","cardinality":"One","final":false,"encrypted":false},"version":{"name":"version","id":1344,"since":31,"type":"String","cardinality":"One","final":false,"encrypted":false}},"associations":{},"app":"sys","version":"31"} | ||
| +export const SignOrderProcessingAgreementDataTypeRef: TypeRef<SignOrderProcessingAgreementData> = new TypeRef("sys", "SignOrderProcessingAgreementData") | ||
| +export const _TypeModel: TypeModel = { | ||
| + "name": "SignOrderProcessingAgreementData", | ||
| + "since": 31, | ||
| + "type": "DATA_TRANSFER_TYPE", | ||
| + "id": 1342, | ||
| + "rootId": "A3N5cwAFPg", | ||
| + "versioned": false, | ||
| + "encrypted": false, | ||
| + "values": { | ||
| + "_format": { | ||
| + "name": "_format", | ||
| + "id": 1343, | ||
| + "since": 31, | ||
| + "type": "Number", | ||
| + "cardinality": "One", | ||
| + "final": false, | ||
| + "encrypted": false | ||
| + }, | ||
| + "customerAddress": { | ||
| + "name": "customerAddress", | ||
| + "id": 1345, | ||
| + "since": 31, | ||
| + "type": "String", | ||
| + "cardinality": "One", | ||
| + "final": false, | ||
| + "encrypted": false | ||
| + }, | ||
| + "version": { | ||
| + "name": "version", | ||
| + "id": 1344, | ||
| + "since": 31, | ||
| + "type": "String", | ||
| + "cardinality": "One", | ||
| + "final": false, | ||
| + "encrypted": false | ||
| + } | ||
| + }, | ||
| + "associations": {}, | ||
| + "app": "sys", | ||
| + "version": "32" | ||
| +} | ||
| -export function createSignOrderProcessingAgreementData():SignOrderProcessingAgreementData { | ||
| - return create(_TypeModel) | ||
| +export function createSignOrderProcessingAgreementData(): SignOrderProcessingAgreementData { | ||
| + return create(_TypeModel) | ||
| } |
| @@ -0,0 +1,50 @@ | ||
| +// @flow | ||
| +import {create, TypeRef} from "../../common/EntityFunctions" | ||
| + | ||
| +export const SseConnectDataTypeRef: TypeRef<SseConnectData> = new TypeRef("sys", "SseConnectData") | ||
| +export const _TypeModel: TypeModel = { | ||
| + "name": "SseConnectData", | ||
| + "since": 32, | ||
| + "type": "DATA_TRANSFER_TYPE", | ||
| + "id": 1352, | ||
| + "rootId": "A3N5cwAFSA", | ||
| + "versioned": false, | ||
| + "encrypted": false, | ||
| + "values": { | ||
| + "_format": { | ||
| + "name": "_format", | ||
| + "id": 1353, | ||
| + "since": 32, | ||
| + "type": "Number", | ||
| + "cardinality": "One", | ||
| + "final": false, | ||
| + "encrypted": false | ||
| + }, | ||
| + "identifier": { | ||
| + "name": "identifier", | ||
| + "id": 1354, | ||
| + "since": 32, | ||
| + "type": "String", | ||
| + "cardinality": "One", | ||
| + "final": true, | ||
| + "encrypted": false | ||
| + } | ||
| + }, | ||
| + "associations": { | ||
| + "userIds": { | ||
| + "name": "userIds", | ||
| + "id": 1355, | ||
| + "since": 32, | ||
| + "type": "AGGREGATION", | ||
| + "cardinality": "Any", | ||
| + "refType": "GeneratedIdWrapper", | ||
| + "final": false | ||
| + } | ||
| + }, | ||
| + "app": "sys", | ||
| + "version": "32" | ||
| +} | ||
| + | ||
| +export function createSseConnectData(): SseConnectData { | ||
| + return create(_TypeModel) | ||
| +} |