diff options
| author | Adam Soltys <[email protected]> | 2022-10-05 12:15:48 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2022-10-05 12:15:48 -0700 |
| commit | fb91aa048617f0894e01c1e890ec957a3170539f (patch) | |
| tree | 5630fbe3bb5eb67fc0fba2bba79b8b763609d93a | |
| parent | 160d95f693d7d8a17e864313b06790a841d4e160 (diff) | |
| download | coinos-server-fb91aa048617f0894e01c1e890ec957a3170539f.tar.gz coinos-server-fb91aa048617f0894e01c1e890ec957a3170539f.zip | |
prettier
| -rw-r--r-- | apidoc/api_data.js | 1302 | ||||
| -rw-r--r-- | apidoc/api_project.js | 26 | ||||
| -rw-r--r-- | apidoc/main.js | 1796 | ||||
| -rw-r--r-- | db/models/invoices.js | 4 | ||||
| -rw-r--r-- | lib/binance.js | 2 | ||||
| -rw-r--r-- | lib/buildliquidtx.js | 2 | ||||
| -rw-r--r-- | lib/persist.js | 4 | ||||
| -rw-r--r-- | lib/rates.js | 4 | ||||
| -rw-r--r-- | lib/rpc.js | 3 | ||||
| -rw-r--r-- | lib/send.js | 10 | ||||
| -rw-r--r-- | lib/sendInternal.js | 17 | ||||
| -rw-r--r-- | lib/sockets.js | 2 | ||||
| -rw-r--r-- | lib/utils.js | 5 | ||||
| -rw-r--r-- | routes/bitcoin/receive.js | 3 | ||||
| -rw-r--r-- | routes/info.js | 102 | ||||
| -rw-r--r-- | routes/invoices.js | 25 | ||||
| -rw-r--r-- | routes/lightning/receive.js | 4 | ||||
| -rw-r--r-- | routes/liquid/receive.js | 3 | ||||
| -rw-r--r-- | routes/lnurl.js | 99 | ||||
| -rw-r--r-- | routes/payments.js | 2 | ||||
| -rw-r--r-- | routes/users.js | 114 | ||||
| -rw-r--r-- | sampleconfig/lnurl.js | 29 |
22 files changed, 1901 insertions, 1657 deletions
diff --git a/apidoc/api_data.js b/apidoc/api_data.js index 63c793fa..44a2a9c4 100644 --- a/apidoc/api_data.js +++ b/apidoc/api_data.js @@ -1,742 +1,762 @@ -define({ "api": [ - { - "type": "get", - "url": "/accounts", - "title": "Retrieve list of accounts", - "name": "accounts", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "optional": false, - "field": "returns", - "description": "<p>list of accounts</p>" - } - ] - }, - "examples": [ +define({ + api: [ + { + type: "get", + url: "/accounts", + title: "Retrieve list of accounts", + name: "accounts", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"accounts\" : [\n { \"user\": 'Adam', \"account_id\": '123', balance: 500 ... },\n ...\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/deposits", - "title": "Retrieve summary of deposits", - "name": "deposits", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "returns", + description: "<p>list of accounts</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "returns", - "description": "<p>list of deposits</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "accounts" : [\n { "user": \'Adam\', "account_id": \'123\', balance: 500 ... },\n ...\n ]\n}', + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" + }, + { + type: "get", + url: "/deposits", + title: "Retrieve summary of deposits", + name: "deposits", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"deposits\" : [\n { \"seller\": 'Adam', \"buyer\": 'bob' ... },\n ...\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/users", - "title": "Retrieve user list", - "name": "getUsers", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "returns", + description: "<p>list of deposits</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "users", - "description": "<p>List of users</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "deposits" : [\n { "seller": \'Adam\', "buyer": \'bob\' ... },\n ...\n ]\n}', + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" + }, + { + type: "get", + url: "/users", + title: "Retrieve user list", + name: "getUsers", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"users\" : [\n { \"username\": 'John Doe', \"email\": '[email protected]', ...},\n { \"username\": 'Jane Doe', \"email\": '[email protected]', ...}\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/invoices", - "title": "Retrieve summary of invoices", - "name": "invoices", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + type: "Object", + optional: false, + field: "users", + description: "<p>List of users</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "returns", - "description": "<p>list of invoices</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "users" : [\n { "username": \'John Doe\', "email": \'[email protected]\', ...},\n { "username": \'Jane Doe\', "email": \'[email protected]\', ...}\n ]\n}', + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" + }, + { + type: "get", + url: "/invoices", + title: "Retrieve summary of invoices", + name: "invoices", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"invoices\" : [\n { \"seller\": 'Adam', \"buyer\": 'bob' ... },\n ...\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/orders", - "title": "Retrieve summary of orders", - "name": "orders", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "returns", + description: "<p>list of invoices</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "returns", - "description": "<p>list of orders</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "invoices" : [\n { "seller": \'Adam\', "buyer": \'bob\' ... },\n ...\n ]\n}', + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" + }, + { + type: "get", + url: "/orders", + title: "Retrieve summary of orders", + name: "orders", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"orders\" : [\n { \"seller\": 'Adam', \"buyer\": 'bob' ... },\n ...\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/payments", - "title": "Retrieve summary of payments", - "name": "payments", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "returns", + description: "<p>list of orders</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "returns", - "description": "<p>list of payments</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "orders" : [\n { "seller": \'Adam\', "buyer": \'bob\' ... },\n ...\n ]\n}', + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" + }, + { + type: "get", + url: "/payments", + title: "Retrieve summary of payments", + name: "payments", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"payments\" : [\n { \"seller\": 'Adam', \"buyer\": 'bob' ... },\n ...\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/referrals", - "title": "Retrieve list of referral tokens", - "name": "referrals", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "returns", + description: "<p>list of payments</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "returns", - "description": "<p>list of referral tokens</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "payments" : [\n { "seller": \'Adam\', "buyer": \'bob\' ... },\n ...\n ]\n}', + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" + }, + { + type: "get", + url: "/referrals", + title: "Retrieve list of referral tokens", + name: "referrals", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"referrals\" : [\n { \"token\": '***', \"status\": 'pending', sponsor: 'Adam', user: 'newUsername1', expiry: null },\n { \"token\": '***', \"status\": 'pending', sponsor: 'Adam', user: 'newUsername2', expiry: null },\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/referrals", - "title": "Retrieve list of referral tokens", - "name": "referrals", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "returns", + description: "<p>list of referral tokens</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "returns", - "description": "<p>list of referral tokens</p>" + title: "Success-Response:", + content: + "HTTP/1.1 200 OK\n{\n \"referrals\" : [\n { \"token\": '***', \"status\": 'pending', sponsor: 'Adam', user: 'newUsername1', expiry: null },\n { \"token\": '***', \"status\": 'pending', sponsor: 'Adam', user: 'newUsername2', expiry: null },\n ]\n}", + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" + }, + { + type: "get", + url: "/referrals", + title: "Retrieve list of referral tokens", + name: "referrals", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"referrals\" : [\n { \"token\": '***', \"status\": 'pending', sponsor: 'Adam', user: 'newUsername1', expiry: null },\n { \"token\": '***', \"status\": 'pending', sponsor: 'Adam', user: 'newUsername2', expiry: null },\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/user_kyc", - "title": "Retrieve user kyc details", - "name": "user_kyc", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "returns", + description: "<p>list of referral tokens</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "returns", - "description": "<p>list of kyc details for each user</p>" + title: "Success-Response:", + content: + "HTTP/1.1 200 OK\n{\n \"referrals\" : [\n { \"token\": '***', \"status\": 'pending', sponsor: 'Adam', user: 'newUsername1', expiry: null },\n { \"token\": '***', \"status\": 'pending', sponsor: 'Adam', user: 'newUsername2', expiry: null },\n ]\n}", + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" + }, + { + type: "get", + url: "/user_kyc", + title: "Retrieve user kyc details", + name: "user_kyc", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"users\" : [\n { \"username\": 'Adam', \"email\": '[email protected]', ... kyc_data... },\n ...\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/transactions", - "title": "Retrieve summary of user transactions", - "name": "user_transactions", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "returns", + description: "<p>list of kyc details for each user</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "returns", - "description": "<p>list of invoices, payments, orders for users</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "users" : [\n { "username": \'Adam\', "email": \'[email protected]\', ... kyc_data... },\n ...\n ]\n}', + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" + }, + { + type: "get", + url: "/transactions", + title: "Retrieve summary of user transactions", + name: "user_transactions", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"transactions\" : [\n { \"username\": 'Adam', \"email\": '[email protected]', invoices: 1, orders: 0, payments: 2 },\n ...\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/withdrawals", - "title": "Retrieve summary of withdrawals", - "name": "withdrawals", - "group": "Admin", - "permission": [ - { - "name": "admin" - } - ], - "success": { - "fields": { - "Success 200": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "returns", + description: "<p>list of invoices, payments, orders for users</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "returns", - "description": "<p>list of withdrawals</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "transactions" : [\n { "username": \'Adam\', "email": \'[email protected]\', invoices: 1, orders: 0, payments: 2 },\n ...\n ]\n}', + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" + }, + { + type: "get", + url: "/withdrawals", + title: "Retrieve summary of withdrawals", + name: "withdrawals", + group: "Admin", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"withdrawals\" : [\n { \"seller\": 'Adam', \"buyer\": 'bob' ... },\n ...\n ]\n}", - "type": "json" + name: "admin" } - ] - }, - "version": "0.0.0", - "filename": "routes/admin.js", - "groupTitle": "Admin" - }, - { - "type": "get", - "url": "/info", - "title": "Request server information", - "name": "GetInfo", - "group": "Info", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "fx", - "description": "<p>Exchange rates relative to USD - fx.CUR is the value of one CUR in USD.</p>" - }, - { - "group": "Success 200", - "type": "String[]", - "optional": false, - "field": "networks", - "description": "<p>Array of supported networks; possible values are "bitcoin", "liquid" and "lightning".</p>" - }, - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "clientVersion", - "description": "<p>the current git commit of the ui</p>" - } - ] - } - }, - "version": "0.0.0", - "filename": "routes/info.js", - "groupTitle": "Info" - }, - { - "type": "post", - "url": "/grant", - "title": "Grant Referral code", - "name": "Grant", - "group": "Referrals", - "permission": [ - { - "name": "member" - } - ], - "parameter": { - "fields": { - "Parameter": [ + ], + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "returns", + description: "<p>list of withdrawals</p>" + } + ] + }, + examples: [ { - "group": "Parameter", - "type": "sponsor_id", - "optional": false, - "field": "user_id", - "description": "<p>of member generating referral code.</p>" - }, - { - "group": "Parameter", - "type": "expiry", - "optional": false, - "field": "optional", - "description": "<p>expiry date for token.</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "withdrawals" : [\n { "seller": \'Adam\', "buyer": \'bob\' ... },\n ...\n ]\n}', + type: "json" } ] - } + }, + version: "0.0.0", + filename: "routes/admin.js", + groupTitle: "Admin" }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "token", - "description": "<p>referral token</p>" - }, - { - "group": "Success 200", - "type": "Date", - "optional": false, - "field": "expiry", - "description": "<p>optional expiry</p>" - } - ] + { + type: "get", + url: "/info", + title: "Request server information", + name: "GetInfo", + group: "Info", + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + type: "Object", + optional: false, + field: "fx", + description: + "<p>Exchange rates relative to USD - fx.CUR is the value of one CUR in USD.</p>" + }, + { + group: "Success 200", + type: "String[]", + optional: false, + field: "networks", + description: + "<p>Array of supported networks; possible values are "bitcoin", "liquid" and "lightning".</p>" + }, + { + group: "Success 200", + type: "String", + optional: false, + field: "clientVersion", + description: "<p>the current git commit of the ui</p>" + } + ] + } }, - "examples": [ + version: "0.0.0", + filename: "routes/info.js", + groupTitle: "Info" + }, + { + type: "post", + url: "/grant", + title: "Grant Referral code", + name: "Grant", + group: "Referrals", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"token\": \"*********\", \n \"status\": \"available\", \n \"expiry\": null\n}", - "type": "json" + name: "member" + } + ], + parameter: { + fields: { + Parameter: [ + { + group: "Parameter", + type: "sponsor_id", + optional: false, + field: "user_id", + description: "<p>of member generating referral code.</p>" + }, + { + group: "Parameter", + type: "expiry", + optional: false, + field: "optional", + description: "<p>expiry date for token.</p>" + } + ] } - ] - }, - "version": "0.0.0", - "filename": "routes/referrals.js", - "groupTitle": "Referrals" - }, - { - "type": "get", - "url": "/grant", - "title": "Grant Referral code (variation using get)", - "name": "Grant", - "group": "Referrals", - "permission": [ - { - "name": "member" }, - { - "name": "member" - } - ], - "parameter": { - "fields": { - "Parameter": [ + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + type: "String", + optional: false, + field: "token", + description: "<p>referral token</p>" + }, + { + group: "Success 200", + type: "Date", + optional: false, + field: "expiry", + description: "<p>optional expiry</p>" + } + ] + }, + examples: [ { - "group": "Parameter", - "type": "sponsor_id", - "optional": false, - "field": "user_id", - "description": "<p>of member generating referral code.</p>" - }, - { - "group": "Parameter", - "type": "expiry", - "optional": false, - "field": "optional", - "description": "<p>expiry date for token.</p>" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "token", - "description": "<p>referral token</p>" - }, - { - "group": "Success 200", - "type": "Status", - "optional": false, - "field": "status", - "description": "<p>referral status</p>" - }, - { - "group": "Success 200", - "type": "Date", - "optional": false, - "field": "expiry", - "description": "<p>optional expiry</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "token": "*********", \n "status": "available", \n "expiry": null\n}', + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/referrals.js", + groupTitle: "Referrals" + }, + { + type: "get", + url: "/grant", + title: "Grant Referral code (variation using get)", + name: "Grant", + group: "Referrals", + permission: [ + { + name: "member" + }, { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"token\": \"*********\", \n \"status\": \"available\", \n \"expiry\": null\n}", - "type": "json" + name: "member" } - ] - }, - "version": "0.0.0", - "filename": "routes/referrals.js", - "groupTitle": "Referrals" - }, - { - "type": "get", - "url": "/checkTokens/:sponsor_id", - "title": "Retrieve list of referral tokens generated by this user", - "name": "checkTokens", - "group": "Referrals", - "permission": [ - { - "name": "member" - } - ], - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "sponsor_id", - "optional": false, - "field": "user_id", - "description": "<p>of member generating referral code.</p>" - }, - { - "group": "Parameter", - "type": "status", - "optional": false, - "field": "optional", - "description": "<p>token status.</p>" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ + ], + parameter: { + fields: { + Parameter: [ + { + group: "Parameter", + type: "sponsor_id", + optional: false, + field: "user_id", + description: "<p>of member generating referral code.</p>" + }, + { + group: "Parameter", + type: "expiry", + optional: false, + field: "optional", + description: "<p>expiry date for token.</p>" + } + ] + } + }, + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + type: "String", + optional: false, + field: "token", + description: "<p>referral token</p>" + }, + { + group: "Success 200", + type: "Status", + optional: false, + field: "status", + description: "<p>referral status</p>" + }, + { + group: "Success 200", + type: "Date", + optional: false, + field: "expiry", + description: "<p>optional expiry</p>" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "tokens", - "description": "<p>array of token objects</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "token": "*********", \n "status": "available", \n "expiry": null\n}', + type: "json" } ] }, - "examples": [ + version: "0.0.0", + filename: "routes/referrals.js", + groupTitle: "Referrals" + }, + { + type: "get", + url: "/checkTokens/:sponsor_id", + title: "Retrieve list of referral tokens generated by this user", + name: "checkTokens", + group: "Referrals", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"tokens\": [\n {\"token\": \"*********\", \"status\": \"available\", \"expiry\": null}\n ]\n}", - "type": "json" + name: "member" } - ] - }, - "version": "0.0.0", - "filename": "routes/referrals.js", - "groupTitle": "Referrals" - }, - { - "type": "get", - "url": "/isReferred/:user_id", - "title": "Check if user is referred", - "name": "isReferred", - "group": "Referrals", - "parameter": { - "fields": { - "Parameter": [ + ], + parameter: { + fields: { + Parameter: [ + { + group: "Parameter", + type: "sponsor_id", + optional: false, + field: "user_id", + description: "<p>of member generating referral code.</p>" + }, + { + group: "Parameter", + type: "status", + optional: false, + field: "optional", + description: "<p>token status.</p>" + } + ] + } + }, + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "tokens", + description: "<p>array of token objects</p>" + } + ] + }, + examples: [ { - "group": "Parameter", - "type": "user_id", - "optional": false, - "field": "user", - "description": "<p>id</p>" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "tokens": [\n {"token": "*********", "status": "available", "expiry": null}\n ]\n}', + type: "json" } ] - } + }, + version: "0.0.0", + filename: "routes/referrals.js", + groupTitle: "Referrals" }, - "success": { - "examples": [ - { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n true\n}", - "type": "json" + { + type: "get", + url: "/isReferred/:user_id", + title: "Check if user is referred", + name: "isReferred", + group: "Referrals", + parameter: { + fields: { + Parameter: [ + { + group: "Parameter", + type: "user_id", + optional: false, + field: "user", + description: "<p>id</p>" + } + ] } - ] - }, - "description": "<p>returns boolean indicating if user is referred or not</p>", - "version": "0.0.0", - "filename": "routes/referrals.js", - "groupTitle": "Referrals" - }, - { - "type": "post", - "url": "/joinQueue", - "title": "Join waiting list (track email & phone)", - "name": "joinQueue", - "group": "Referrals", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "email", - "optional": false, - "field": "email", - "description": "<p>address</p>" - }, + }, + success: { + examples: [ { - "group": "Parameter", - "type": "phone", - "optional": false, - "field": "phone", - "description": "<p>number</p>" + title: "Success-Response:", + content: "HTTP/1.1 200 OK\n{\n true\n}", + type: "json" } ] - } + }, + description: + "<p>returns boolean indicating if user is referred or not</p>", + version: "0.0.0", + filename: "routes/referrals.js", + groupTitle: "Referrals" }, - "success": { - "fields": { - "Success 200": [ + { + type: "post", + url: "/joinQueue", + title: "Join waiting list (track email & phone)", + name: "joinQueue", + group: "Referrals", + parameter: { + fields: { + Parameter: [ + { + group: "Parameter", + type: "email", + optional: false, + field: "email", + description: "<p>address</p>" + }, + { + group: "Parameter", + type: "phone", + optional: false, + field: "phone", + description: "<p>number</p>" + } + ] + } + }, + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "verified", + defaultValue: "true", + description: "" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "verified", - "defaultValue": "true", - "description": "" + title: "Success-Response:", + content: + 'HTTP/1.1 200 OK\n{\n "success": true\n "message": \'Added to waiting list\'\n}', + type: "json" } ] }, - "examples": [ + description: "<p>referral token is updated with existing user_id</p>", + version: "0.0.0", + filename: "routes/referrals.js", + groupTitle: "Referrals" + }, + { + type: "get", + url: "/verify/:user_id", + title: "Verify token and apply to existing user", + name: "verify", + group: "Referrals", + permission: [ { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"success\": true\n \"message\": 'Added to waiting list'\n}", - "type": "json" + name: "member" } - ] - }, - "description": "<p>referral token is updated with existing user_id</p>", - "version": "0.0.0", - "filename": "routes/referrals.js", - "groupTitle": "Referrals" - }, - { - "type": "get", - "url": "/verify/:user_id", - "title": "Verify token and apply to existing user", - "name": "verify", - "group": "Referrals", - "permission": [ - { - "name": "member" - } - ], - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "user_id", - "optional": false, - "field": "Current", - "description": "<p>user</p>" - }, - { - "group": "Parameter", - "type": "token", - "optional": false, - "field": "Token", - "description": "<p>to validate</p>" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ + ], + parameter: { + fields: { + Parameter: [ + { + group: "Parameter", + type: "user_id", + optional: false, + field: "Current", + description: "<p>user</p>" + }, + { + group: "Parameter", + type: "token", + optional: false, + field: "Token", + description: "<p>to validate</p>" + } + ] + } + }, + success: { + fields: { + "Success 200": [ + { + group: "Success 200", + optional: false, + field: "verified", + defaultValue: "true", + description: "" + } + ] + }, + examples: [ { - "group": "Success 200", - "optional": false, - "field": "verified", - "defaultValue": "true", - "description": "" + title: "Success-Response:", + content: 'HTTP/1.1 200 OK\n{\n "verified": true\n}', + type: "json" } ] }, - "examples": [ - { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n \"verified\": true\n}", - "type": "json" - } - ] - }, - "description": "<p>referral token is updated with existing user_id</p>", - "version": "0.0.0", - "filename": "routes/referrals.js", - "groupTitle": "Referrals" - } -] }); + description: "<p>referral token is updated with existing user_id</p>", + version: "0.0.0", + filename: "routes/referrals.js", + groupTitle: "Referrals" + } + ] +}); diff --git a/apidoc/api_project.js b/apidoc/api_project.js index b382cf76..3c0eb6aa 100644 --- a/apidoc/api_project.js +++ b/apidoc/api_project.js @@ -1,16 +1,16 @@ define({ - "title": "CoinOS Server API Documentation", - "url": "https://coinos.io/api", - "name": "coinos", - "version": "0.0.1", - "description": "", - "sampleUrl": false, - "defaultVersion": "0.0.0", - "apidoc": "0.3.0", - "generator": { - "name": "apidoc", - "time": "2021-08-18T19:13:24.486Z", - "url": "https://apidocjs.com", - "version": "0.29.0" + title: "CoinOS Server API Documentation", + url: "https://coinos.io/api", + name: "coinos", + version: "0.0.1", + description: "", + sampleUrl: false, + defaultVersion: "0.0.0", + apidoc: "0.3.0", + generator: { + name: "apidoc", + time: "2021-08-18T19:13:24.486Z", + url: "https://apidocjs.com", + version: "0.29.0" } }); diff --git a/apidoc/main.js b/apidoc/main.js index ea4801b0..bdcf58cb 100644 --- a/apidoc/main.js +++ b/apidoc/main.js @@ -1,952 +1,1146 @@ require.config({ - paths: { - bootstrap: './vendor/bootstrap.min', - diffMatchPatch: './vendor/diff_match_patch.min', - handlebars: './vendor/handlebars.min', - handlebarsExtended: './utils/handlebars_helper', - jquery: './vendor/jquery.min', - locales: './locales/locale', - lodash: './vendor/lodash.custom.min', - pathToRegexp: './vendor/path-to-regexp/index', - prismjs: './vendor/prism', - semver: './vendor/semver.min', - utilsSampleRequest: './utils/send_sample_request', - webfontloader: './vendor/webfontloader', - list: './vendor/list.min', - apiData: './api_data', - apiProject: './api_project', + paths: { + bootstrap: "./vendor/bootstrap.min", + diffMatchPatch: "./vendor/diff_match_patch.min", + handlebars: "./vendor/handlebars.min", + handlebarsExtended: "./utils/handlebars_helper", + jquery: "./vendor/jquery.min", + locales: "./locales/locale", + lodash: "./vendor/lodash.custom.min", + pathToRegexp: "./vendor/path-to-regexp/index", + prismjs: "./vendor/prism", + semver: "./vendor/semver.min", + utilsSampleRequest: "./utils/send_sample_request", + webfontloader: "./vendor/webfontloader", + list: "./vendor/list.min", + apiData: "./api_data", + apiProject: "./api_project" + }, + shim: { + bootstrap: { + deps: ["jquery"] }, - shim: { - bootstrap: { - deps: ['jquery'] - }, - diffMatchPatch: { - exports: 'diff_match_patch' - }, - handlebars: { - exports: 'Handlebars' - }, - handlebarsExtended: { - deps: ['jquery', 'handlebars'], - exports: 'Handlebars' - }, - prismjs: { - exports: 'Prism' - }, + diffMatchPatch: { + exports: "diff_match_patch" }, - urlArgs: 'v=' + (new Date()).getTime(), - waitSeconds: 150 + handlebars: { + exports: "Handlebars" + }, + handlebarsExtended: { + deps: ["jquery", "handlebars"], + exports: "Handlebars" + }, + prismjs: { + exports: "Prism" + } + }, + urlArgs: "v=" + new Date().getTime(), + waitSeconds: 150 }); require([ - 'jquery', - 'lodash', - 'locales', - 'handlebarsExtended', - 'apiProject', - 'apiData', - 'prismjs', - 'utilsSampleRequest', - 'semver', - 'webfontloader', - 'bootstrap', - 'pathToRegexp', - 'list' -], function($, _, locale, Handlebars, apiProject, apiData, Prism, sampleRequest, semver, WebFont) { - - // Load google web fonts. - WebFont.load({ - active: function() { - // Only init after fonts are loaded. - init($, _, locale, Handlebars, apiProject, apiData, Prism, sampleRequest, semver); - }, - inactive: function() { - // Run init, even if loading fonts fails - init($, _, locale, Handlebars, apiProject, apiData, Prism, sampleRequest, semver); - }, - google: { - families: ['Source Code Pro', 'Source Sans Pro:n4,n6,n7'] - } - }); + "jquery", + "lodash", + "locales", + "handlebarsExtended", + "apiProject", + "apiData", + "prismjs", + "utilsSampleRequest", + "semver", + "webfontloader", + "bootstrap", + "pathToRegexp", + "list" +], function( + $, + _, + locale, + Handlebars, + apiProject, + apiData, + Prism, + sampleRequest, + semver, + WebFont +) { + // Load google web fonts. + WebFont.load({ + active: function() { + // Only init after fonts are loaded. + init( + $, + _, + locale, + Handlebars, + apiProject, + apiData, + Prism, + sampleRequest, + semver + ); + }, + inactive: function() { + // Run init, even if loading fonts fails + init( + $, + _, + locale, + Handlebars, + apiProject, + apiData, + Prism, + sampleRequest, + semver + ); + }, + google: { + families: ["Source Code Pro", "Source Sans Pro:n4,n6,n7"] + } + }); }); -function init($, _, locale, Handlebars, apiProject, apiData, Prism, sampleRequest, semver) { - var api = apiData.api; +function init( + $, + _, + locale, + Handlebars, + apiProject, + apiData, + Prism, + sampleRequest, + semver +) { + var api = apiData.api; - // - // Templates - // - var templateHeader = Handlebars.compile( $('#template-header').html() ); - var templateFooter = Handlebars.compile( $('#template-footer').html() ); - var templateArticle = Handlebars.compile( $('#template-article').html() ); - var templateCompareArticle = Handlebars.compile( $('#template-compare-article').html() ); - var templateGenerator = Handlebars.compile( $('#template-generator').html() ); - var templateProject = Handlebars.compile( $('#template-project').html() ); - var templateSections = Handlebars.compile( $('#template-sections').html() ); - var templateSidenav = Handlebars.compile( $('#template-sidenav').html() ); + // + // Templates + // + var templateHeader = Handlebars.compile($("#template-header").html()); + var templateFooter = Handlebars.compile($("#template-footer").html()); + var templateArticle = Handlebars.compile($("#template-article").html()); + var templateCompareArticle = Handlebars.compile( + $("#template-compare-article").html() + ); + var templateGenerator = Handlebars.compile($("#template-generator").html()); + var templateProject = Handlebars.compile($("#template-project").html()); + var templateSections = Handlebars.compile($("#template-sections").html()); + var templateSidenav = Handlebars.compile($("#template-sidenav").html()); - // - // Default host url used if no sampleUrl is present in config - // - var baseURL = window.location.origin; + // + // Default host url used if no sampleUrl is present in config + // + var baseURL = window.location.origin; - // - // apiProject defaults - // - if ( ! apiProject.template) - apiProject.template = {}; + // + // apiProject defaults + // + if (!apiProject.template) apiProject.template = {}; - if (apiProject.template.withCompare == null) - apiProject.template.withCompare = true; + if (apiProject.template.withCompare == null) + apiProject.template.withCompare = true; - if (apiProject.template.withGenerator == null) - apiProject.template.withGenerator = true; + if (apiProject.template.withGenerator == null) + apiProject.template.withGenerator = true; - if (apiProject.template.forceLanguage) - locale.setLanguage(apiProject.template.forceLanguage); + if (apiProject.template.forceLanguage) + locale.setLanguage(apiProject.template.forceLanguage); - if (apiProject.template.aloneDisplay == null) - apiProject.template.aloneDisplay = false; + if (apiProject.template.aloneDisplay == null) + apiProject.template.aloneDisplay = false; - // Setup jQuery Ajax - $.ajaxSetup(apiProject.template.jQueryAjaxSetup); + // Setup jQuery Ajax + $.ajaxSetup(apiProject.template.jQueryAjaxSetup); - // - // Data transform - // - // grouped by group - var apiByGroup = _.groupBy(api, function(entry) { - return entry.group; - }); + // + // Data transform + // + // grouped by group + var apiByGroup = _.groupBy(api, function(entry) { + return entry.group; + }); - // grouped by group and name - var apiByGroupAndName = {}; - $.each(apiByGroup, function(index, entries) { - apiByGroupAndName[index] = _.groupBy(entries, function(entry) { - return entry.name; - }); + // grouped by group and name + var apiByGroupAndName = {}; + $.each(apiByGroup, function(index, entries) { + apiByGroupAndName[index] = _.groupBy(entries, function(entry) { + return entry.name; }); + }); - // - // sort api within a group by title ASC and custom order - // - var newList = []; - var umlauts = { 'ä': 'ae', 'ü': 'ue', 'ö': 'oe', 'ß': 'ss' }; // TODO: remove in version 1.0 - $.each (apiByGroupAndName, function(index, groupEntries) { - // get titles from the first entry of group[].name[] (name has versioning) - var titles = []; - $.each (groupEntries, function(titleName, entries) { - var title = entries[0].title; - if(title !== undefined) { - title.toLowerCase().replace(/[äöüß]/g, function($0) { return umlauts[$0]; }); - titles.push(title + '#~#' + titleName); // '#~#' keep reference to titleName after sorting - } + // + // sort api within a group by title ASC and custom order + // + var newList = []; + var umlauts = { ä: "ae", ü: "ue", ö: "oe", ß: "ss" }; // TODO: remove in version 1.0 + $.each(apiByGroupAndName, function(index, groupEntries) { + // get titles from the first entry of group[].name[] (name has versioning) + var titles = []; + $.each(groupEntries, function(titleName, entries) { + var title = entries[0].title; + if (title !== undefined) { + title.toLowerCase().replace(/[äöüß]/g, function($0) { + return umlauts[$0]; }); - // sort by name ASC - titles.sort(); + titles.push(title + "#~#" + titleName); // '#~#' keep reference to titleName after sorting + } + }); + // sort by name ASC + titles.sort(); - // custom order - if (apiProject.order) - titles = sortByOrder(titles, apiProject.order, '#~#'); + // custom order + if (apiProject.order) titles = sortByOrder(titles, apiProject.order, "#~#"); - // add single elements to the new list - titles.forEach(function(name) { - var values = name.split('#~#'); - var key = values[1]; - groupEntries[key].forEach(function(entry) { - newList.push(entry); - }); - }); + // add single elements to the new list + titles.forEach(function(name) { + var values = name.split("#~#"); + var key = values[1]; + groupEntries[key].forEach(function(entry) { + newList.push(entry); + }); }); - // api overwrite with ordered list - api = newList; + }); + // api overwrite with ordered list + api = newList; - // - // Group- and Versionlists - // - var apiGroups = {}; - var apiGroupTitles = {}; - var apiVersions = {}; - apiVersions[apiProject.version] = 1; + // + // Group- and Versionlists + // + var apiGroups = {}; + var apiGroupTitles = {}; + var apiVersions = {}; + apiVersions[apiProject.version] = 1; - $.each(api, function(index, entry) { - apiGroups[entry.group] = 1; - apiGroupTitles[entry.group] = entry.groupTitle || entry.group; - apiVersions[entry.version] = 1; - }); + $.each(api, function(index, entry) { + apiGroups[entry.group] = 1; + apiGroupTitles[entry.group] = entry.groupTitle || entry.group; + apiVersions[entry.version] = 1; + }); - // sort groups - apiGroups = Object.keys(apiGroups); - apiGroups.sort(); + // sort groups + apiGroups = Object.keys(apiGroups); + apiGroups.sort(); - // custom order - if (apiProject.order) - apiGroups = sortByOrder(apiGroups, apiProject.order); + // custom order + if (apiProject.order) apiGroups = sortByOrder(apiGroups, apiProject.order); - // sort versions DESC - apiVersions = Object.keys(apiVersions); - apiVersions.sort(semver.compare); - apiVersions.reverse(); + // sort versions DESC + apiVersions = Object.keys(apiVersions); + apiVersions.sort(semver.compare); + apiVersions.reverse(); - // - // create Navigationlist - // - var nav = []; - apiGroups.forEach(function(group) { - // Mainmenu entry - nav.push({ - group: group, - isHeader: true, - title: apiGroupTitles[group] - }); + // + // create Navigationlist + // + var nav = []; + apiGroups.forEach(function(group) { + // Mainmenu entry + nav.push({ + group: group, + isHeader: true, + title: apiGroupTitles[group] + }); - // Submenu - var oldName = ''; - api.forEach(function(entry) { - if (entry.group === group) { - if (oldName !== entry.name) { - nav.push({ - title: entry.title, - group: group, - name: entry.name, - type: entry.type, - version: entry.version, - url: entry.url - }); - } else { - nav.push({ - title: entry.title, - group: group, - hidden: true, - name: entry.name, - type: entry.type, - version: entry.version, - url: entry.url - }); - } - oldName = entry.name; - } - }); + // Submenu + var oldName = ""; + api.forEach(function(entry) { + if (entry.group === group) { + if (oldName !== entry.name) { + nav.push({ + title: entry.title, + group: group, + name: entry.name, + type: entry.type, + version: entry.version, + url: entry.url + }); + } else { + nav.push({ + title: entry.title, + group: group, + hidden: true, + name: entry.name, + type: entry.type, + version: entry.version, + url: entry.url + }); + } + oldName = entry.name; + } }); + }); - /** - * Add navigation items by analyzing the HTML content and searching for h1 and h2 tags - * @param nav Object the navigation array - * @param content string the compiled HTML content - * @param index where to insert items - * @return boolean true if any good-looking (i.e. with a group identifier) <h1> tag was found - */ - function add_nav(nav, content, index) { - var found_level1 = false; - if ( ! content) { - return found_level1; + /** + * Add navigation items by analyzing the HTML content and searching for h1 and h2 tags + * @param nav Object the navigation array + * @param content string the compiled HTML content + * @param index where to insert items + * @return boolean true if any good-looking (i.e. with a group identifier) <h1> tag was found + */ + function add_nav(nav, content, index) { + var found_level1 = false; + if (!content) { + return found_level1; + } + var topics = content.match(/<h(1|2).*?>(.+?)<\/h(1|2)>/gi); + if (topics) { + topics.forEach(function(entry) { + var level = entry.substring(2, 3); + var title = entry.replace(/<.+?>/g, ""); // Remove all HTML tags for the title + var entry_tags = entry.match(/id="api-([^\-]+)(?:-(.+))?"/); // Find the group and name in the id property + var group = entry_tags ? entry_tags[1] : null; + var name = entry_tags ? entry_tags[2] : null; + if (level == 1 && title && group) { + nav.splice(index, 0, { + group: group, + isHeader: true, + title: title, + isFixed: true + }); + index++; + found_level1 = true; } - var topics = content.match(/<h(1|2).*?>(.+?)<\/h(1|2)>/gi); - if ( topics ) { - topics.forEach(function(entry) { - var level = entry.substring(2,3); - var title = entry.replace(/<.+?>/g, ''); // Remove all HTML tags for the title - var entry_tags = entry.match(/id="api-([^\-]+)(?:-(.+))?"/); // Find the group and name in the id property - var group = (entry_tags ? entry_tags[1] : null); - var name = (entry_tags ? entry_tags[2] : null); - if (level==1 && title && group) { - nav.splice(index, 0, { - group: group, - isHeader: true, - title: title, - isFixed: true - }); - index++; - found_level1 = true; - } - if (level==2 && title && group && name) { - nav.splice(index, 0, { - group: group, - name: name, - isHeader: false, - title: title, - isFixed: false, - version: '1.0' - }); - index++; - } + if (level == 2 && title && group && name) { + nav.splice(index, 0, { + group: group, + name: name, + isHeader: false, + title: title, + isFixed: false, + version: "1.0" }); + index++; } - return found_level1; + }); } + return found_level1; + } - // Mainmenu Header entry - if (apiProject.header) { - var found_level1 = add_nav(nav, apiProject.header.content, 0); // Add level 1 and 2 titles - if (!found_level1) { // If no Level 1 tags were found, make a title - nav.unshift({ - group: '_', - isHeader: true, - title: (apiProject.header.title == null) ? locale.__('General') : apiProject.header.title, - isFixed: true - }); - } + // Mainmenu Header entry + if (apiProject.header) { + var found_level1 = add_nav(nav, apiProject.header.content, 0); // Add level 1 and 2 titles + if (!found_level1) { + // If no Level 1 tags were found, make a title + nav.unshift({ + group: "_", + isHeader: true, + title: + apiProject.header.title == null + ? locale.__("General") + : apiProject.header.title, + isFixed: true + }); } + } - // Mainmenu Footer entry - if (apiProject.footer) { - var last_nav_index = nav.length; - var found_level1 = add_nav(nav, apiProject.footer.content, nav.length); // Add level 1 and 2 titles - if (!found_level1 && apiProject.footer.title != null) { // If no Level 1 tags were found, make a title - nav.splice(last_nav_index, 0, { - group: '_footer', - isHeader: true, - title: apiProject.footer.title, - isFixed: true - }); - } + // Mainmenu Footer entry + if (apiProject.footer) { + var last_nav_index = nav.length; + var found_level1 = add_nav(nav, apiProject.footer.content, nav.length); // Add level 1 and 2 titles + if (!found_level1 && apiProject.footer.title != null) { + // If no Level 1 tags were found, make a title + nav.splice(last_nav_index, 0, { + group: "_footer", + isHeader: true, + title: apiProject.footer.title, + isFixed: true + }); } + } - // render pagetitle - var title = apiProject.title ? apiProject.title : 'apiDoc: ' + apiProject.name + ' - ' + apiProject.version; - $(document).attr('title', title); + // render pagetitle + var title = apiProject.title + ? apiProject.title + : "apiDoc: " + apiProject.name + " - " + apiProject.version; + $(document).attr("title", title); - // remove loader - $('#loader').remove(); + // remove loader + $("#loader").remove(); - // render sidenav - var fields = { - nav: nav - }; - $('#sidenav').append( templateSidenav(fields) ); + // render sidenav + var fields = { + nav: nav + }; + $("#sidenav").append(templateSidenav(fields)); - // render Generator - $('#generator').append( templateGenerator(apiProject) ); + // render Generator + $("#generator").append(templateGenerator(apiProject)); - // render Project - _.extend(apiProject, { versions: apiVersions}); - $('#project').append( templateProject(apiProject) ); + // render Project + _.extend(apiProject, { versions: apiVersions }); + $("#project").append(templateProject(apiProject)); - // render apiDoc, header/footer documentation - if (apiProject.header) - $('#header').append( templateHeader(apiProject.header) ); + // render apiDoc, header/footer documentation + if (apiProject.header) $("#header").append(templateHeader(apiProject.header)); - if (apiProject.footer) - $('#footer').append( templateFooter(apiProject.footer) ); + if (apiProject.footer) $("#footer").append(templateFooter(apiProject.footer)); - // - // Render Sections and Articles - // - var articleVersions = {}; - var content = ''; - apiGroups.forEach(function(groupEntry) { - var articles = []; - var oldName = ''; - var fields = {}; - var title = groupEntry; - var description = ''; - articleVersions[groupEntry] = {}; + // + // Render Sections and Articles + // + var articleVersions = {}; + var content = ""; + apiGroups.forEach(function(groupEntry) { + var articles = []; + var oldName = ""; + var fields = {}; + var title = groupEntry; + var description = ""; + articleVersions[groupEntry] = {}; - // render all articles of a group - api.forEach(function(entry) { - if(groupEntry === entry.group) { - if (oldName !== entry.name) { - // determine versions - api.forEach(function(versionEntry) { - if (groupEntry === versionEntry.group && entry.name === versionEntry.name) { - if ( ! articleVersions[entry.group].hasOwnProperty(entry.name) ) { - articleVersions[entry.group][entry.name] = []; - } - articleVersions[entry.group][entry.name].push(versionEntry.version); - } - }); - fields = { - article: entry, - versions: articleVersions[entry.group][entry.name] - }; - } else { - fields = { - article: entry, - hidden: true, - versions: articleVersions[entry.group][entry.name] - }; - } + // render all articles of a group + api.forEach(function(entry) { + if (groupEntry === entry.group) { + if (oldName !== entry.name) { + // determine versions + api.forEach(function(versionEntry) { + if ( + groupEntry === versionEntry.group && + entry.name === versionEntry.name + ) { + if (!articleVersions[entry.group].hasOwnProperty(entry.name)) { + articleVersions[entry.group][entry.name] = []; + } + articleVersions[entry.group][entry.name].push( + versionEntry.version + ); + } + }); + fields = { + article: entry, + versions: articleVersions[entry.group][entry.name] + }; + } else { + fields = { + article: entry, + hidden: true, + versions: articleVersions[entry.group][entry.name] + }; + } - if (apiProject.sampleUrl == false) { - fields.article.sampleRequest = [ - { - "url": baseURL + fields.article.url - } - ]; - } + if (apiProject.sampleUrl == false) { + fields.article.sampleRequest = [ + { + url: baseURL + fields.article.url + } + ]; + } - // add prefix URL for endpoint unless it's already absolute - if (apiProject.url) { - if (fields.article.url.substr(0, 4).toLowerCase() !== 'http') { - fields.article.url = apiProject.url + fields.article.url; - } - } + // add prefix URL for endpoint unless it's already absolute + if (apiProject.url) { + if (fields.article.url.substr(0, 4).toLowerCase() !== "http") { + fields.article.url = apiProject.url + fields.article.url; + } + } - addArticleSettings(fields, entry); + addArticleSettings(fields, entry); - if (entry.groupTitle) - title = entry.groupTitle; + if (entry.groupTitle) title = entry.groupTitle; - // TODO: make groupDescription compareable with older versions (not important for the moment) - if (entry.groupDescription) - description = entry.groupDescription; + // TODO: make groupDescription compareable with older versions (not important for the moment) + if (entry.groupDescription) description = entry.groupDescription; - articles.push({ - article: templateArticle(fields), - group: entry.group, - name: entry.name, - aloneDisplay: apiProject.template.aloneDisplay - }); - oldName = entry.name; - } + articles.push({ + article: templateArticle(fields), + group: entry.group, + name: entry.name, + aloneDisplay: apiProject.template.aloneDisplay }); - - // render Section with Articles - var fields = { - group: groupEntry, - title: title, - description: description, - articles: articles, - aloneDisplay: apiProject.template.aloneDisplay - }; - content += templateSections(fields); + oldName = entry.name; + } }); - $('#sections').append( content ); - // Bootstrap Scrollspy - $(this).scrollspy({ target: '#scrollingNav' }); + // render Section with Articles + var fields = { + group: groupEntry, + title: title, + description: description, + articles: articles, + aloneDisplay: apiProject.template.aloneDisplay + }; + content += templateSections(fields); + }); + $("#sections").append(content); - // Content-Scroll on Navigation click. - $('.sidenav').find('a').on('click', function(e) { - e.preventDefault(); - var id = $(this).attr('href'); - if ($(id).length > 0) - $('html,body').animate({ scrollTop: parseInt($(id).offset().top) }, 400); - window.location.hash = $(this).attr('href'); - }); + // Bootstrap Scrollspy + $(this).scrollspy({ target: "#scrollingNav" }); - /** - * Check if Parameter (sub) List has a type Field. - * Example: @apiSuccess varname1 No type. - * @apiSuccess {String} varname2 With type. - * - * @param {Object} fields - */ - function _hasTypeInFields(fields) { - var result = false; - $.each(fields, function(name) { - result = result || _.some(fields[name], function(item) { return item.type; }); - }); - return result; - } + // Content-Scroll on Navigation click. + $(".sidenav") + .find("a") + .on("click", function(e) { + e.preventDefault(); + var id = $(this).attr("href"); + if ($(id).length > 0) + $("html,body").animate( + { scrollTop: parseInt($(id).offset().top) }, + 400 + ); + window.location.hash = $(this).attr("href"); + }); - /** - * On Template changes, recall plugins. - */ - function initDynamic() { - // Bootstrap popover - $('button[data-toggle="popover"]').popover().click(function(e) { - e.preventDefault(); + /** + * Check if Parameter (sub) List has a type Field. + * Example: @apiSuccess varname1 No type. + * @apiSuccess {String} varname2 With type. + * + * @param {Object} fields + */ + function _hasTypeInFields(fields) { + var result = false; + $.each(fields, function(name) { + result = + result || + _.some(fields[name], function(item) { + return item.type; }); + }); + return result; + } - var version = $('#version strong').html(); - $('#sidenav li').removeClass('is-new'); - if (apiProject.template.withCompare) { - $('#sidenav li[data-version=\'' + version + '\']').each(function(){ - var group = $(this).data('group'); - var name = $(this).data('name'); - var length = $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\']').length; - var index = $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\']').index($(this)); - if (length === 1 || index === (length - 1)) - $(this).addClass('is-new'); - }); - } - - // tabs - $('.nav-tabs-examples a').click(function (e) { - e.preventDefault(); - $(this).tab('show'); - }); - $('.nav-tabs-examples').find('a:first').tab('show'); + /** + * On Template changes, recall plugins. + */ + function initDynamic() { + // Bootstrap popover + $('button[data-toggle="popover"]') + .popover() + .click(function(e) { + e.preventDefault(); + }); - // sample header-content-type switch - $('.sample-header-content-type-switch').change(function () { - var paramName = '.' + $(this).attr('name') + '-fields'; - var bodyName = '.' + $(this).attr('name') + '-body'; - var selectName = 'select[name=' + $(this).attr('name') + ']'; - if ($(this).val() == 'body-json') { - $(selectName).val('undefined'); - $(this).val('body-json'); - $(paramName).removeClass('hide'); - $(this).parent().nextAll(paramName).first().addClass('hide'); - $(bodyName).addClass('hide'); - $(this).parent().nextAll(bodyName).first().removeClass('hide'); - } else if ($(this).val() == "body-form-data") { - $(selectName).val('undefined'); - $(this).val('body-form-data'); - $(bodyName).addClass('hide'); - $(paramName).removeClass('hide'); - } else { - $(this).parent().nextAll(paramName).first().removeClass('hide') - $(this).parent().nextAll(bodyName).first().addClass('hide'); - } - $(this).prev('.sample-request-switch').prop('checked', true); - }); + var version = $("#version strong").html(); + $("#sidenav li").removeClass("is-new"); + if (apiProject.template.withCompare) { + $("#sidenav li[data-version='" + version + "']").each(function() { + var group = $(this).data("group"); + var name = $(this).data("name"); + var length = $( + "#sidenav li[data-group='" + group + "'][data-name='" + name + "']" + ).length; + var index = $( + "#sidenav li[data-group='" + group + "'][data-name='" + name + "']" + ).index($(this)); + if (length === 1 || index === length - 1) $(this).addClass("is-new"); + }); + } - // sample request switch - $('.sample-request-switch').click(function (e) { - var paramName = '.' + $(this).attr('name') + '-fields'; - var bodyName = '.' + $(this).attr('name') + '-body'; - var select = $(this).next('.' + $(this).attr('name') + '-select').val(); - if($(this).prop("checked")){ - if (select == 'body-json'){ - $(this).parent().nextAll(bodyName).first().removeClass('hide'); - }else { - $(this).parent().nextAll(paramName).first().removeClass('hide'); - } - }else { - if (select == 'body-json'){ - $(this).parent().nextAll(bodyName).first().addClass('hide'); - }else { - $(this).parent().nextAll(paramName).first().addClass('hide'); - } - } - }); + // tabs + $(".nav-tabs-examples a").click(function(e) { + e.preventDefault(); + $(this).tab("show"); + }); + $(".nav-tabs-examples") + .find("a:first") + .tab("show"); - if (apiProject.template.aloneDisplay){ - //show group - $('.show-group').click(function () { - var apiGroup = '.' + $(this).attr('data-group') + '-group'; - var apiGroupArticle = '.' + $(this).attr('data-group') + '-article'; - $(".show-api-group").addClass('hide'); - $(apiGroup).removeClass('hide'); - $(".show-api-article").addClass('hide'); - $(apiGroupArticle).removeClass('hide'); - }); + // sample header-content-type switch + $(".sample-header-content-type-switch").change(function() { + var paramName = "." + $(this).attr("name") + "-fields"; + var bodyName = "." + $(this).attr("name") + "-body"; + var selectName = "select[name=" + $(this).attr("name") + "]"; + if ($(this).val() == "body-json") { + $(selectName).val("undefined"); + $(this).val("body-json"); + $(paramName).removeClass("hide"); + $(this) + .parent() + .nextAll(paramName) + .first() + .addClass("hide"); + $(bodyName).addClass("hide"); + $(this) + .parent() + .nextAll(bodyName) + .first() + .removeClass("hide"); + } else if ($(this).val() == "body-form-data") { + $(selectName).val("undefined"); + $(this).val("body-form-data"); + $(bodyName).addClass("hide"); + $(paramName).removeClass("hide"); + } else { + $(this) + .parent() + .nextAll(paramName) + .first() + .removeClass("hide"); + $(this) + .parent() + .nextAll(bodyName) + .first() + .addClass("hide"); + } + $(this) + .prev(".sample-request-switch") + .prop("checked", true); + }); - //show api - $('.show-api').click(function () { - var apiName = '.' + $(this).attr('data-name') + '-article'; - var apiGroup = '.' + $(this).attr('data-group') + '-group'; - $(".show-api-group").addClass('hide'); - $(apiGroup).removeClass('hide'); - $(".show-api-article").addClass('hide'); - $(apiName).removeClass('hide'); - }); + // sample request switch + $(".sample-request-switch").click(function(e) { + var paramName = "." + $(this).attr("name") + "-fields"; + var bodyName = "." + $(this).attr("name") + "-body"; + var select = $(this) + .next("." + $(this).attr("name") + "-select") + .val(); + if ($(this).prop("checked")) { + if (select == "body-json") { + $(this) + .parent() + .nextAll(bodyName) + .first() + .removeClass("hide"); + } else { + $(this) + .parent() + .nextAll(paramName) + .first() + .removeClass("hide"); } + } else { + if (select == "body-json") { + $(this) + .parent() + .nextAll(bodyName) + .first() + .addClass("hide"); + } else { + $(this) + .parent() + .nextAll(paramName) + .first() + .addClass("hide"); + } + } + }); - // call scrollspy refresh method - $(window).scrollspy('refresh'); + if (apiProject.template.aloneDisplay) { + //show group + $(".show-group").click(function() { + var apiGroup = "." + $(this).attr("data-group") + "-group"; + var apiGroupArticle = "." + $(this).attr("data-group") + "-article"; + $(".show-api-group").addClass("hide"); + $(apiGroup).removeClass("hide"); + $(".show-api-article").addClass("hide"); + $(apiGroupArticle).removeClass("hide"); + }); - // init modules - sampleRequest.initDynamic(); - Prism.highlightAll() + //show api + $(".show-api").click(function() { + var apiName = "." + $(this).attr("data-name") + "-article"; + var apiGroup = "." + $(this).attr("data-group") + "-group"; + $(".show-api-group").addClass("hide"); + $(apiGroup).removeClass("hide"); + $(".show-api-article").addClass("hide"); + $(apiName).removeClass("hide"); + }); } - initDynamic(); - if (apiProject.template.aloneDisplay) { - var hashVal = window.location.hash; - if (hashVal != null && hashVal.length !== 0) { - $("." + hashVal.slice(1) + "-init").click(); - } - } + // call scrollspy refresh method + $(window).scrollspy("refresh"); - // - // HTML-Template specific jQuery-Functions - // - // Change Main Version - function setMainVersion(selectedVersion) { - if (typeof(selectedVersion) === 'undefined') { - selectedVersion = $('#version strong').html(); - } - else { - $('#version strong').html(selectedVersion); - } + // init modules + sampleRequest.initDynamic(); + Prism.highlightAll(); + } + initDynamic(); - // hide all - $('article').addClass('hide'); - $('#sidenav li:not(.nav-fixed)').addClass('hide'); + if (apiProject.template.aloneDisplay) { + var hashVal = window.location.hash; + if (hashVal != null && hashVal.length !== 0) { + $("." + hashVal.slice(1) + "-init").click(); + } + } - // show 1st equal or lower Version of each entry - $('article[data-version]').each(function(index) { - var group = $(this).data('group'); - var name = $(this).data('name'); - var version = $(this).data('version'); + // + // HTML-Template specific jQuery-Functions + // + // Change Main Version + function setMainVersion(selectedVersion) { + if (typeof selectedVersion === "undefined") { + selectedVersion = $("#version strong").html(); + } else { + $("#version strong").html(selectedVersion); + } - if (semver.lte(version, selectedVersion)) { - if ($('article[data-group=\'' + group + '\'][data-name=\'' + name + '\']:visible').length === 0) { - // enable Article - $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('hide'); - // enable Navigation - $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('hide'); - $('#sidenav li.nav-header[data-group=\'' + group + '\']').removeClass('hide'); - } - } - }); + // hide all + $("article").addClass("hide"); + $("#sidenav li:not(.nav-fixed)").addClass("hide"); - // show 1st equal or lower Version of each entry - $('article[data-version]').each(function(index) { - var group = $(this).data('group'); - $('section#api-' + group).removeClass('hide'); - if ($('section#api-' + group + ' article:visible').length === 0) { - $('section#api-' + group).addClass('hide'); - } else { - $('section#api-' + group).removeClass('hide'); - } - }); + // show 1st equal or lower Version of each entry + $("article[data-version]").each(function(index) { + var group = $(this).data("group"); + var name = $(this).data("name"); + var version = $(this).data("version"); - initDynamic(); - return; - } - setMainVersion(); - - $('#versions li.version a').on('click', function(e) { - e.preventDefault(); + if (semver.lte(version, selectedVersion)) { + if ( + $( + "article[data-group='" + + group + + "'][data-name='" + + name + + "']:visible" + ).length === 0 + ) { + // enable Article + $( + "article[data-group='" + + group + + "'][data-name='" + + name + + "'][data-version='" + + version + + "']" + ).removeClass("hide"); + // enable Navigation + $( + "#sidenav li[data-group='" + + group + + "'][data-name='" + + name + + "'][data-version='" + + version + + "']" + ).removeClass("hide"); + $("#sidenav li.nav-header[data-group='" + group + "']").removeClass( + "hide" + ); + } + } + }); - setMainVersion($(this).html()); + // show 1st equal or lower Version of each entry + $("article[data-version]").each(function(index) { + var group = $(this).data("group"); + $("section#api-" + group).removeClass("hide"); + if ($("section#api-" + group + " article:visible").length === 0) { + $("section#api-" + group).addClass("hide"); + } else { + $("section#api-" + group).removeClass("hide"); + } }); - // compare all article with their predecessor - $('#compareAllWithPredecessor').on('click', changeAllVersionCompareTo); + initDynamic(); + return; + } + setMainVersion(); - // change version of an article - $('article .versions li.version a').on('click', changeVersionCompareTo); + $("#versions li.version a").on("click", function(e) { + e.preventDefault(); - // compare url-parameter - $.urlParam = function(name) { - var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href); - return (results && results[1]) ? results[1] : null; - }; + setMainVersion($(this).html()); + }); - if ($.urlParam('compare')) { - // URL Paramter ?compare=1 is set - $('#compareAllWithPredecessor').trigger('click'); - } + // compare all article with their predecessor + $("#compareAllWithPredecessor").on("click", changeAllVersionCompareTo); - // Quick jump on page load to hash position. - // Should happen after setting the main version - // and after triggering the click on the compare button, - // as these actions modify the content - // and would make it jump to the wrong position or not jump at all. - if (window.location.hash) { - var id = decodeURI(window.location.hash); - if ($(id).length > 0) - $('html,body').animate({ scrollTop: parseInt($(id).offset().top) }, 0); - } + // change version of an article + $("article .versions li.version a").on("click", changeVersionCompareTo); - /** - * Initialize search - */ - var options = { - valueNames: [ 'nav-list-item','nav-list-url-item'] - }; - var endpointsList = new List('scrollingNav', options); + // compare url-parameter + $.urlParam = function(name) { + var results = new RegExp("[\\?&]" + name + "=([^&#]*)").exec( + window.location.href + ); + return results && results[1] ? results[1] : null; + }; - /** - * Set initial focus to search input - */ - $('#scrollingNav .sidenav-search input.search').focus(); + if ($.urlParam("compare")) { + // URL Paramter ?compare=1 is set + $("#compareAllWithPredecessor").trigger("click"); + } - /** - * Detect ESC key to reset search - */ - $(document).keyup(function(e) { - if (e.keyCode === 27) $('span.search-reset').click(); - }); + // Quick jump on page load to hash position. + // Should happen after setting the main version + // and after triggering the click on the compare button, + // as these actions modify the content + // and would make it jump to the wrong position or not jump at all. + if (window.location.hash) { + var id = decodeURI(window.location.hash); + if ($(id).length > 0) + $("html,body").animate({ scrollTop: parseInt($(id).offset().top) }, 0); + } - /** - * Search reset - */ - $('span.search-reset').on('click', function() { - $('#scrollingNav .sidenav-search input.search') - .val("") - .focus() - ; - endpointsList.search(); - }); + /** + * Initialize search + */ + var options = { + valueNames: ["nav-list-item", "nav-list-url-item"] + }; + var endpointsList = new List("scrollingNav", options); - /** - * Change version of an article to compare it to an other version. - */ - function changeVersionCompareTo(e) { - e.preventDefault(); + /** + * Set initial focus to search input + */ + $("#scrollingNav .sidenav-search input.search").focus(); - var $root = $(this).parents('article'); - var selectedVersion = $(this).html(); - var $button = $root.find('.version'); - var currentVersion = $button.find('strong').html(); - $button.find('strong').html(selectedVersion); + /** + * Detect ESC key to reset search + */ + $(document).keyup(function(e) { + if (e.keyCode === 27) $("span.search-reset").click(); + }); - var group = $root.data('group'); - var name = $root.data('name'); - var version = $root.data('version'); + /** + * Search reset + */ + $("span.search-reset").on("click", function() { + $("#scrollingNav .sidenav-search input.search") + .val("") + .focus(); + endpointsList.search(); + }); - var compareVersion = $root.data('compare-version'); + /** + * Change version of an article to compare it to an other version. + */ + function changeVersionCompareTo(e) { + e.preventDefault(); - if (compareVersion === selectedVersion) - return; + var $root = $(this).parents("article"); + var selectedVersion = $(this).html(); + var $button = $root.find(".version"); + var currentVersion = $button.find("strong").html(); + $button.find("strong").html(selectedVersion); - if ( ! compareVersion && version == selectedVersion) - return; + var group = $root.data("group"); + var name = $root.data("name"); + var version = $root.data("version"); - if (compareVersion && articleVersions[group][name][0] === selectedVersion || version === selectedVersion) { - // the version of the entry is set to the highest version (reset) - resetArticle(group, name, version); - } else { - var $compareToArticle = $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + selectedVersion + '\']'); + var compareVersion = $root.data("compare-version"); - var sourceEntry = {}; - var compareEntry = {}; - $.each(apiByGroupAndName[group][name], function(index, entry) { - if (entry.version === version) - sourceEntry = entry; - if (entry.version === selectedVersion) - compareEntry = entry; - }); + if (compareVersion === selectedVersion) return; - var fields = { - article: sourceEntry, - compare: compareEntry, - versions: articleVersions[group][name] - }; + if (!compareVersion && version == selectedVersion) return; - // add unique id - // TODO: replace all group-name-version in template with id. - fields.article.id = fields.article.group + '-' + fields.article.name + '-' + fields.article.version; - fields.article.id = fields.article.id.replace(/\./g, '_'); + if ( + (compareVersion && articleVersions[group][name][0] === selectedVersion) || + version === selectedVersion + ) { + // the version of the entry is set to the highest version (reset) + resetArticle(group, name, version); + } else { + var $compareToArticle = $( + "article[data-group='" + + group + + "'][data-name='" + + name + + "'][data-version='" + + selectedVersion + + "']" + ); - fields.compare.id = fields.compare.group + '-' + fields.compare.name + '-' + fields.compare.version; - fields.compare.id = fields.compare.id.replace(/\./g, '_'); + var sourceEntry = {}; + var compareEntry = {}; + $.each(apiByGroupAndName[group][name], function(index, entry) { + if (entry.version === version) sourceEntry = entry; + if (entry.version === selectedVersion) compareEntry = entry; + }); - var entry = sourceEntry; - if (entry.parameter && entry.parameter.fields) - fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); + var fields = { + article: sourceEntry, + compare: compareEntry, + versions: articleVersions[group][name] + }; - if (entry.error && entry.error.fields) - fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); + // add unique id + // TODO: replace all group-name-version in template with id. + fields.article.id = + fields.article.group + + "-" + + fields.article.name + + "-" + + fields.article.version; + fields.article.id = fields.article.id.replace(/\./g, "_"); - if (entry.success && entry.success.fields) - fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); + fields.compare.id = + fields.compare.group + + "-" + + fields.compare.name + + "-" + + fields.compare.version; + fields.compare.id = fields.compare.id.replace(/\./g, "_"); - if (entry.info && entry.info.fields) - fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); + var entry = sourceEntry; + if (entry.parameter && entry.parameter.fields) + fields._hasTypeInParameterFields = _hasTypeInFields( + entry.parameter.fields + ); - var entry = compareEntry; - if (fields._hasTypeInParameterFields !== true && entry.parameter && entry.parameter.fields) - fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); + if (entry.error && entry.error.fields) + fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); - if (fields._hasTypeInErrorFields !== true && entry.error && entry.error.fields) - fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); + if (entry.success && entry.success.fields) + fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); - if (fields._hasTypeInSuccessFields !== true && entry.success && entry.success.fields) - fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); + if (entry.info && entry.info.fields) + fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); - if (fields._hasTypeInInfoFields !== true && entry.info && entry.info.fields) - fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); + var entry = compareEntry; + if ( + fields._hasTypeInParameterFields !== true && + entry.parameter && + entry.parameter.fields + ) + fields._hasTypeInParameterFields = _hasTypeInFields( + entry.parameter.fields + ); - var content = templateCompareArticle(fields); - $root.after(content); - var $content = $root.next(); + if ( + fields._hasTypeInErrorFields !== true && + entry.error && + entry.error.fields + ) + fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); - // Event on.click re-assign - $content.find('.versions li.version a').on('click', changeVersionCompareTo); + if ( + fields._hasTypeInSuccessFields !== true && + entry.success && + entry.success.fields + ) + fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); - // select navigation - $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + currentVersion + '\']').addClass('has-modifications'); + if ( + fields._hasTypeInInfoFields !== true && + entry.info && + entry.info.fields + ) + fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); - $root.remove(); - // TODO: on change main version or select the highest version re-render - } + var content = templateCompareArticle(fields); + $root.after(content); + var $content = $root.next(); + + // Event on.click re-assign + $content + .find(".versions li.version a") + .on("click", changeVersionCompareTo); - initDynamic(); + // select navigation + $( + "#sidenav li[data-group='" + + group + + "'][data-name='" + + name + + "'][data-version='" + + currentVersion + + "']" + ).addClass("has-modifications"); + + $root.remove(); + // TODO: on change main version or select the highest version re-render } - /** - * Compare all currently selected Versions with their predecessor. - */ - function changeAllVersionCompareTo(e) { - e.preventDefault(); - $('article:visible .versions').each(function(){ - var $root = $(this).parents('article'); - var currentVersion = $root.data('version'); - var $foundElement = null; - $(this).find('li.version a').each(function() { - var selectVersion = $(this).html(); - if (selectVersion < currentVersion && ! $foundElement) - $foundElement = $(this); - }); + initDynamic(); + } - if($foundElement) - $foundElement.trigger('click'); + /** + * Compare all currently selected Versions with their predecessor. + */ + function changeAllVersionCompareTo(e) { + e.preventDefault(); + $("article:visible .versions").each(function() { + var $root = $(this).parents("article"); + var currentVersion = $root.data("version"); + var $foundElement = null; + $(this) + .find("li.version a") + .each(function() { + var selectVersion = $(this).html(); + if (selectVersion < currentVersion && !$foundElement) + $foundElement = $(this); }); - initDynamic(); - } - /** - * Sort the fields. - */ - function sortFields(fields_object) { - $.each(fields_object, function (key, fields) { - // Find only object fields - var objects = fields.filter(function(item) { return item.type === "Object"; }); + if ($foundElement) $foundElement.trigger("click"); + }); + initDynamic(); + } - // Check if has any object - if (objects.length === 0) { - return; - } + /** + * Sort the fields. + */ + function sortFields(fields_object) { + $.each(fields_object, function(key, fields) { + // Find only object fields + var objects = fields.filter(function(item) { + return item.type === "Object"; + }); - // Iterate over all objects - for(var object of objects) { - // Retrieve the index - var index = fields.indexOf(object); + // Check if has any object + if (objects.length === 0) { + return; + } - // Find all child fields for this object - var objectFields = fields.filter(function(item) { return item.field.indexOf(object.field + ".") > -1; }); + // Iterate over all objects + for (var object of objects) { + // Retrieve the index + var index = fields.indexOf(object); - // Get the child index - var firstIndex = fields.indexOf(objectFields[0]); + // Find all child fields for this object + var objectFields = fields.filter(function(item) { + return item.field.indexOf(object.field + ".") > -1; + }); - // Put the object it before the first child index - fields.splice(index, 1); - fields.splice(firstIndex, 0, object); + // Get the child index + var firstIndex = fields.indexOf(objectFields[0]); - // Startup the last index with the object index - var lastIndex = firstIndex; + // Put the object it before the first child index + fields.splice(index, 1); + fields.splice(firstIndex, 0, object); - // Iterate over all children - for(var child of objectFields) { - lastIndex++; + // Startup the last index with the object index + var lastIndex = firstIndex; - // Retrieve the index - var childIndex = fields.indexOf(child); + // Iterate over all children + for (var child of objectFields) { + lastIndex++; - // Put it after the object declaration - fields.splice(childIndex, 1); - fields.splice(lastIndex, 0, child); - } - } + // Retrieve the index + var childIndex = fields.indexOf(child); - // Retrieve the first object field index - var firstObjectIndex = fields.indexOf(objects[0]); + // Put it after the object declaration + fields.splice(childIndex, 1); + fields.splice(lastIndex, 0, child); + } + } - // Find all non-object fields that doesn't contain dot notation - var nonObjects = fields.filter(function(item) { return item.field.indexOf(".") === -1 && item.type !== "Object"; }); + // Retrieve the first object field index + var firstObjectIndex = fields.indexOf(objects[0]); - // Iterate over all non-objects - for(var nonObject of nonObjects) { - // Put it before the first object field - var index = fields.indexOf(nonObject); - fields.splice(index, 1); - fields.splice(firstObjectIndex, 0, nonObject); - } - }); - } + // Find all non-object fields that doesn't contain dot notation + var nonObjects = fields.filter(function(item) { + return item.field.indexOf(".") === -1 && item.type !== "Object"; + }); - /** - * Add article settings. - */ - function addArticleSettings(fields, entry) { - // add unique id - // TODO: replace all group-name-version in template with id. - fields.id = fields.article.group + '-' + fields.article.name + '-' + fields.article.version; - fields.id = fields.id.replace(/\./g, '_'); + // Iterate over all non-objects + for (var nonObject of nonObjects) { + // Put it before the first object field + var index = fields.indexOf(nonObject); + fields.splice(index, 1); + fields.splice(firstObjectIndex, 0, nonObject); + } + }); + } - if (entry.header && entry.header.fields) { - sortFields(entry.header.fields); - fields._hasTypeInHeaderFields = _hasTypeInFields(entry.header.fields); - } + /** + * Add article settings. + */ + function addArticleSettings(fields, entry) { + // add unique id + // TODO: replace all group-name-version in template with id. + fields.id = + fields.article.group + + "-" + + fields.article.name + + "-" + + fields.article.version; + fields.id = fields.id.replace(/\./g, "_"); - if (entry.parameter && entry.parameter.fields) { - sortFields(entry.parameter.fields); - fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); - } + if (entry.header && entry.header.fields) { + sortFields(entry.header.fields); + fields._hasTypeInHeaderFields = _hasTypeInFields(entry.header.fields); + } - if (entry.error && entry.error.fields) { - sortFields(entry.error.fields); - fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); - } + if (entry.parameter && entry.parameter.fields) { + sortFields(entry.parameter.fields); + fields._hasTypeInParameterFields = _hasTypeInFields( + entry.parameter.fields + ); + } - if (entry.success && entry.success.fields) { - sortFields(entry.success.fields); - fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); - } + if (entry.error && entry.error.fields) { + sortFields(entry.error.fields); + fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); + } - if (entry.info && entry.info.fields) { - sortFields(entry.info.fields); - fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); - } + if (entry.success && entry.success.fields) { + sortFields(entry.success.fields); + fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); + } - // add template settings - fields.template = apiProject.template; + if (entry.info && entry.info.fields) { + sortFields(entry.info.fields); + fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); } - /** - * Render Article. - */ - function renderArticle(group, name, version) { - var entry = {}; - $.each(apiByGroupAndName[group][name], function(index, currentEntry) { - if (currentEntry.version === version) - entry = currentEntry; - }); - var fields = { - article: entry, - versions: articleVersions[group][name] - }; + // add template settings + fields.template = apiProject.template; + } - addArticleSettings(fields, entry); + /** + * Render Article. + */ + function renderArticle(group, name, version) { + var entry = {}; + $.each(apiByGroupAndName[group][name], function(index, currentEntry) { + if (currentEntry.version === version) entry = currentEntry; + }); + var fields = { + article: entry, + versions: articleVersions[group][name] + }; - return templateArticle(fields); - } + addArticleSettings(fields, entry); - /** - * Render original Article and remove the current visible Article. - */ - function resetArticle(group, name, version) { - var $root = $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\']:visible'); - var content = renderArticle(group, name, version); + return templateArticle(fields); + } - $root.after(content); - var $content = $root.next(); + /** + * Render original Article and remove the current visible Article. + */ + function resetArticle(group, name, version) { + var $root = $( + "article[data-group='" + group + "'][data-name='" + name + "']:visible" + ); + var content = renderArticle(group, name, version); - // Event on.click needs to be reassigned (should actually work with on ... automatically) - $content.find('.versions li.version a').on('click', changeVersionCompareTo); + $root.after(content); + var $content = $root.next(); - $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('has-modifications'); + // Event on.click needs to be reassigned (should actually work with on ... automatically) + $content.find(".versions li.version a").on("click", changeVersionCompareTo); - $root.remove(); - return; - } + $( + "#sidenav li[data-group='" + + group + + "'][data-name='" + + name + + "'][data-version='" + + version + + "']" + ).removeClass("has-modifications"); - /** - * Return ordered entries by custom order and append not defined entries to the end. - * @param {String[]} elements - * @param {String[]} order - * @param {String} splitBy - * @return {String[]} Custom ordered list. - */ - function sortByOrder(elements, order, splitBy) { - var results = []; - order.forEach (function(name) { - if (splitBy) - elements.forEach (function(element) { - var parts = element.split(splitBy); - var key = parts[0]; // reference keep for sorting - if (key == name || parts[1] == name) - results.push(element); - }); - else - elements.forEach (function(key) { - if (key == name) - results.push(name); - }); - }); - // Append all other entries that ar not defined in order + $root.remove(); + return; + } + + /** + * Return ordered entries by custom order and append not defined entries to the end. + * @param {String[]} elements + * @param {String[]} order + * @param {String} splitBy + * @return {String[]} Custom ordered list. + */ + function sortByOrder(elements, order, splitBy) { + var results = []; + order.forEach(function(name) { + if (splitBy) elements.forEach(function(element) { - if (results.indexOf(element) === -1) - results.push(element); + var parts = element.split(splitBy); + var key = parts[0]; // reference keep for sorting + if (key == name || parts[1] == name) results.push(element); }); - return results; - } - Prism.highlightAll() + else + elements.forEach(function(key) { + if (key == name) results.push(name); + }); + }); + // Append all other entries that ar not defined in order + elements.forEach(function(element) { + if (results.indexOf(element) === -1) results.push(element); + }); + return results; + } + Prism.highlightAll(); } diff --git a/db/models/invoices.js b/db/models/invoices.js index d93e9214..b13a9545 100644 --- a/db/models/invoices.js +++ b/db/models/invoices.js @@ -130,8 +130,8 @@ const attributes = { }, received: { type: DataTypes.STRING(255), - allowNull: true, - defaultValue: null, + allowNull: false, + defaultValue: 0, primaryKey: false, autoIncrement: false, comment: null, diff --git a/lib/binance.js b/lib/binance.js index f81c8cc3..9f7f149f 100644 --- a/lib/binance.js +++ b/lib/binance.js @@ -28,7 +28,7 @@ export default () => { }; binance.onerror = async function(error) { - console.log(error) + console.log(error); err("binance socket error", error.message); }; diff --git a/lib/buildliquidtx.js b/lib/buildliquidtx.js index f2dce6e1..bd1a2b00 100644 --- a/lib/buildliquidtx.js +++ b/lib/buildliquidtx.js @@ -1,7 +1,7 @@ import store from "./store"; import { prod } from "./utils"; import axios from "axios"; -import liquid from 'liquidjs-lib'; +import liquid from "liquidjs-lib"; import coinselect from "coinselect"; import split from "coinselect/split"; const api = prod diff --git a/lib/persist.js b/lib/persist.js index 12020283..fd6fb146 100644 --- a/lib/persist.js +++ b/lib/persist.js @@ -4,7 +4,9 @@ export default (path, initial = {}) => { if (!initial || !Object.keys(initial).length) { try { initial = JSON.parse(fs.readFileSync("/app/" + path)); - } catch (e) { console.log(e) } + } catch (e) { + console.log(e); + } } return new Proxy(initial, { diff --git a/lib/rates.js b/lib/rates.js index a4a620ea..e896c8cc 100644 --- a/lib/rates.js +++ b/lib/rates.js @@ -31,7 +31,9 @@ let fetchRates; try { let { data: { rates: fx } - } = await axios.get(`https://api.exchangerate.host/latest?base=USD&v={(new Date()).toISOString().split('T')[0]}`); + } = await axios.get( + `https://api.exchangerate.host/latest?base=USD&v={(new Date()).toISOString().split('T')[0]}` + ); fs.writeFileSync("fx", JSON.stringify({ date, fx })); } catch (e) { try { @@ -18,8 +18,7 @@ export default ({ host, port, wallet, username, password }) => method, params }) - .json(({ result }) => result) + .json(({ result }) => result); })(prop.toLowerCase(), ...params) - } ); diff --git a/lib/send.js b/lib/send.js index e7255219..5997b379 100644 --- a/lib/send.js +++ b/lib/send.js @@ -68,10 +68,7 @@ export default async (amount, memo, hash, user) => { conversionFeeDeduction = Math.min(account.lightning_credits, conversionFee); total = amount + conversionFee - conversionFeeDeduction; - if ( - !account || - account.balance < total - ) { + if (!account || account.balance < total) { warn( "user attempting to send more than they have", user.id, @@ -104,7 +101,10 @@ export default async (amount, memo, hash, user) => { ({ fee, secret, tokens: total } = m); preimage = secret.toString("hex"); } else { - let { msatoshi, msatoshi_sent, payment_preimage } = await ln.pay(hash, tokens ? `${tokens}sats` : undefined); + let { msatoshi, msatoshi_sent, payment_preimage } = await ln.pay( + hash, + tokens ? `${tokens}sats` : undefined + ); preimage = payment_preimage; fee = parseInt((msatoshi_sent - msatoshi) / 1000); total = parseInt(msatoshi / 1000); diff --git a/lib/sendInternal.js b/lib/sendInternal.js index 80701ca3..fbe4d95f 100644 --- a/lib/sendInternal.js +++ b/lib/sendInternal.js @@ -10,15 +10,11 @@ import { sendLiquid } from "$routes/liquid/send"; import { l, err } from "$lib/logging"; import { fail } from "$lib/utils"; -export default async ({ - amount, - address, - payreq, - unconfidential, - asset, - memo, - username, -}, hostname, user) => { +export default async ( + { amount, address, payreq, unconfidential, asset, memo, username }, + hostname, + user +) => { amount = parseInt(amount); if (!asset) asset = config.liquid.btcasset; @@ -209,9 +205,8 @@ export default async ({ l("received internal", recipient.username, amount); notify(recipient, `Received ${amount} ${a2.ticker} sats`); callWebhook(invoice, p2); - } - return payment; + return payment; }); }; diff --git a/lib/sockets.js b/lib/sockets.js index 33d1d208..a8428d2f 100644 --- a/lib/sockets.js +++ b/lib/sockets.js @@ -135,7 +135,7 @@ app.register(async function(app) { }); let accounts = await user.getAccounts(); - + let keys = await user.getKeys(); user = user.get({ plain: true }); user.accounts = accounts; diff --git a/lib/utils.js b/lib/utils.js index 036ccd6d..2941bf9d 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -162,8 +162,9 @@ export const derivePayRequest = async ({ amount, memo, tip }) => { if (config.lna.clightning) { if (!memo) memo = "coinos"; - return (await ln.invoice(value ? `${value}sat` : "any", new Date(), memo, 360)) - .bolt11; + return ( + await ln.invoice(value ? `${value}sat` : "any", new Date(), memo, 360) + ).bolt11; } else { return ( await createInvoice({ diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js index 3bc1750d..665cc2bc 100644 --- a/routes/bitcoin/receive.js +++ b/routes/bitcoin/receive.js @@ -231,9 +231,12 @@ setInterval(async () => { { transaction } ); await account.reload({ transaction }); + await invoice.reload({ transaction }); await p.save({ transaction }); p = p.get({ plain: true }); + p.account = account.get({ plain: true }); + p.invoice = invoice.get({ plain: true }); emit(user.username, "account", account); emit(user.username, "payment", p); diff --git a/routes/info.js b/routes/info.js index fd77c5d1..6c2c601d 100644 --- a/routes/info.js +++ b/routes/info.js @@ -37,63 +37,63 @@ app.get("/info", async (req, res, next) => { app.get("/balances", async (req, res, next) => { try { - const accounts = await db.Account.findAll({ - attributes: [ - "asset", - "pubkey", - [sequelize.fn("sum", sequelize.col("balance")), "total"] - ], - group: ["asset", "pubkey"] - }); + const accounts = await db.Account.findAll({ + attributes: [ + "asset", + "pubkey", + [sequelize.fn("sum", sequelize.col("balance")), "total"] + ], + group: ["asset", "pubkey"] + }); - let lnchannel; - let lnwallet; + let lnchannel; + let lnwallet; - if (config.lna) { - if (config.lna.clightning) { - const funds = await ln.listfunds(); - lnchannel = parseInt( - funds.channels.reduce((a, b) => a + b.channel_sat, 0) - ); - lnwallet = parseInt(funds.outputs.reduce((a, b) => a + b.value, 0)); - } else { - lnchannel = parseInt(await getChannelBalance({ lnd }).channel_balance); - lnwallet = parseInt(await getChainBalance({ lnd }).chain_balance); + if (config.lna) { + if (config.lna.clightning) { + const funds = await ln.listfunds(); + lnchannel = parseInt( + funds.channels.reduce((a, b) => a + b.channel_sat, 0) + ); + lnwallet = parseInt(funds.outputs.reduce((a, b) => a + b.value, 0)); + } else { + lnchannel = parseInt(await getChannelBalance({ lnd }).channel_balance); + lnwallet = parseInt(await getChainBalance({ lnd }).chain_balance); + } } - } - let bitcoin, bitcoind; - if (config.bitcoin) { - bitcoin = parseInt((await bc.getBalance()) * SATS); - bitcoind = await bc.getNetworkInfo(); - } + let bitcoin, bitcoind; + if (config.bitcoin) { + bitcoin = parseInt((await bc.getBalance()) * SATS); + bitcoind = await bc.getNetworkInfo(); + } - let assets, liquid, elementsd; - if (config.liquid) { - assets = await lq.getBalance(); - liquid = parseInt(assets.bitcoin * SATS); - elementsd = await lq.getNetworkInfo(); - } + let assets, liquid, elementsd; + if (config.liquid) { + assets = await lq.getBalance(); + liquid = parseInt(assets.bitcoin * SATS); + elementsd = await lq.getNetworkInfo(); + } - const info = { - bitcoind, - elementsd, - accounts, - assets, - bitcoin, - liquid, - lnchannel, - lnwallet - }; + const info = { + bitcoind, + elementsd, + accounts, + assets, + bitcoin, + liquid, + lnchannel, + lnwallet + }; - info.total = - parseInt(bitcoin) + - parseInt(liquid) + - parseInt(lnchannel) + - parseInt(lnwallet); + info.total = + parseInt(bitcoin) + + parseInt(liquid) + + parseInt(lnchannel) + + parseInt(lnwallet); - res.send(info); - } catch(e) { - console.log("problem getting balances", e) - } + res.send(info); + } catch (e) { + console.log("problem getting balances", e); + } }); diff --git a/routes/invoices.js b/routes/invoices.js index 895fb778..f843d663 100644 --- a/routes/invoices.js +++ b/routes/invoices.js @@ -24,7 +24,29 @@ app.get("/invoice", async (req, res, next) => { res.send(invoice); } catch (e) { - err("couldn't find invoice", e); + err("invoice not found", e); + res.code(500).send("Invoice not found"); + } +}); + +app.get("/invoice/:text", async (req, res, next) => { + try { + let { text } = req.params; + const invoice = await db.Invoice.findOne({ + where: { + [Op.or]: [{ unconfidential: text }, { address: text }, { text }] + }, + include: { + model: db.User, + as: "user", + attributes: ["username", "currency"] + } + }); + + res.send(invoice); + } catch (e) { + err("invoice not found", e); + res.code(500).send("Invoice not found"); } }); @@ -73,7 +95,6 @@ app.post("/invoice", optionalAuth, async (req, res, next) => { address = address; } } else if (network !== "lightning") { - console.log(network, { bitcoin: bc, liquid: lq }[network]) address = await { bitcoin: bc, liquid: lq }[network].getNewAddress(); if (network === "liquid") ({ unconfidential } = await lq.getAddressInfo(address)); diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js index 898152fe..2ca6f960 100644 --- a/routes/lightning/receive.js +++ b/routes/lightning/receive.js @@ -82,7 +82,7 @@ const handlePayment = async msg => { { transaction } ); await account.reload({ transaction }); - await invoice.save({ transaction }); + await invoice.reload({ transaction }); await payment.save({ transaction }); store.payments.push(msg.request); @@ -92,6 +92,8 @@ const handlePayment = async msg => { callWebhook(invoice, payment); + console.log("INVOICE", payment.invoice.received); + emit(user.username, "payment", payment); emit(user.username, "account", payment.account); notify(user, `Received ${total} SAT`); diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index cb5c5444..2cd0e957 100644 --- a/routes/liquid/receive.js +++ b/routes/liquid/receive.js @@ -355,10 +355,13 @@ setInterval(async () => { { transaction } ); await p.account.reload({ transaction }); + await p.invoice.reload({ transaction }); await p.save({ transaction }); p = p.get({ plain: true }); + p.account = p.account.get({ plain: true }); + p.invoice = p.invoice.get({ plain: true }); emit(user.username, "account", p.account); emit(user.username, "payment", p); diff --git a/routes/lnurl.js b/routes/lnurl.js index d5c03bf1..6ca61c93 100644 --- a/routes/lnurl.js +++ b/routes/lnurl.js @@ -19,7 +19,7 @@ import { createInvoice, decodePaymentRequest, getPayments } from "lightning"; import { computeConversionFee, - conversionFeeReceiver, + conversionFeeReceiver } from "./lightning/conversionFee.js"; import send from "$lib/send"; @@ -36,8 +36,8 @@ app.get("/url", async (req, res, next) => { try { const code = await db.Code.findOne({ where: { - code: req.query.code, - }, + code: req.query.code + } }); if (code) { @@ -56,7 +56,7 @@ app.get("/withdraw", auth, async (req, res, next) => { const result = await lnurlServer.generateNewUrl("withdrawRequest", { minWithdrawable: min * 1000, maxWithdrawable: max * 1000, - defaultDescription: "coinos voucher", + defaultDescription: "coinos voucher" }); withdrawals[result.secret] = req.user; @@ -74,8 +74,8 @@ app.post("/code", async (req, res, next) => { const code = await db.Code.findOrCreate({ where: { code: `lnurl:${encoded.substr(-32)}`, - text: encoded, - }, + text: encoded + } }); res.send(code); @@ -89,7 +89,7 @@ app.post("/withdraw", auth, async (req, res, next) => { const { user } = req; const { amount: value, - params: { callback, k1 }, + params: { callback, k1 } } = req.body; let invoice; @@ -112,7 +112,7 @@ app.post("/withdraw", auth, async (req, res, next) => { currency: user.currency, amount: value, tip: 0, - network: "bitcoin", + network: "bitcoin" }); try { @@ -129,8 +129,8 @@ app.get("/lnurlp/:username", async (req, res, next) => { const { username } = req.params; let user = await db.User.findOne({ where: { - username, - }, + username + } }); if (!user) throw new Error("user not found"); @@ -145,14 +145,14 @@ app.get("/lnurlp/:username", async (req, res, next) => { maxSendable, metadata: JSON.stringify([ ["text/plain", `paying ${user.username}`], - ["text/identifier", `${user.username}@coinos.io`], - ]), + ["text/identifier", `${user.username}@coinos.io`] + ]) }); recipients[result.secret] = { id: user.id, currency: user.currency, - username, + username }; l("recipient", user.username, result.secret); @@ -170,8 +170,8 @@ app.get("/pay/:username", async (req, res, next) => { const { username } = req.params; let user = await db.User.findOne({ where: { - username, - }, + username + } }); let { amount, minSendable, maxSendable } = req.query; @@ -185,14 +185,14 @@ app.get("/pay/:username", async (req, res, next) => { maxSendable, metadata: JSON.stringify([ ["text/plain", `paying ${user.username}`], - ["text/identifier", `${user.username}@coinos.io`], - ]), + ["text/identifier", `${user.username}@coinos.io`] + ]) }); recipients[result.secret] = { id: user.id, currency: user.currency, - username, + username }; l("recipient", user.username, result.secret); @@ -208,12 +208,11 @@ app.post("/pay", auth, async (req, res, next) => { const { amount, comment, - params: { callback, k1 }, + params: { callback, k1 } } = req.body; - let url = `${callback}${callback.includes("?") ? "&" : "?"}amount=${ - amount * 1000 - }${comment ? "&comment=" + comment : ""}`; + let url = `${callback}${callback.includes("?") ? "&" : "?"}amount=${amount * + 1000}${comment ? "&comment=" + comment : ""}`; try { const parts = callback.split("/"); @@ -225,7 +224,7 @@ app.post("/pay", auth, async (req, res, next) => { { amount, memo: comment, - username: recipients[secret].username, + username: recipients[secret].username }, req.hostname, user @@ -279,7 +278,7 @@ app.get("/decode", async (req, res, next) => { .split("/")[0] .split("@") .slice(-1)[0] - .split(":")[0], + .split(":")[0] }); } @@ -292,7 +291,7 @@ app.get("/decode", async (req, res, next) => { } }); -lnurlServer.on("payRequest:action:processed", async function (event) { +lnurlServer.on("payRequest:action:processed", async function(event) { const { secret, params, result } = event; const { id, invoice } = result; const recipient = recipients[secret]; @@ -306,7 +305,7 @@ lnurlServer.on("payRequest:action:processed", async function (event) { currency: recipient.currency, amount: payreq.satoshis, tip: 0, - network: "lightning", + network: "lightning" }); l("invoice created", i.text, i.amount); @@ -333,8 +332,8 @@ lnurlServer.bindToHook( where: { user_id, asset: config.liquid.btcasset, - pubkey: null, - }, + pubkey: null + } }); if (account.balance < amount) { @@ -352,9 +351,9 @@ lnurlServer.bindToHook( include: [ { model: db.User, - as: "user", - }, - ], + as: "user" + } + ] }); if (keyObj) ({ user } = keyObj); @@ -370,7 +369,7 @@ lnurlServer.bindToHook( user = await register( { username, - password: key, + password: key }, ip ); @@ -399,34 +398,34 @@ lnurlServer.bindToHook( } else { ({ num_satoshis: amount } = await decodePaymentRequest({ lnd, - request: pr, + request: pr })); } let conversionFee = computeConversionFee(amount); - await db.transaction(async (transaction) => { + await db.transaction(async transaction => { let account = await db.Account.findOne({ where: { user_id: user.id, - asset: config.liquid.btcasset, + asset: config.liquid.btcasset }, lock: transaction.LOCK.UPDATE, - transaction, + transaction }); // account that receives conversion fees let receiverAccount = await db.Account.findOne({ where: { - "$user.username$": conversionFeeReceiver, + "$user.username$": conversionFeeReceiver }, include: [ { model: db.User, - as: "user", - }, + as: "user" + } ], lock: transaction.LOCK.UPDATE, - transaction, + transaction }); let conversionFeeDeduction = Math.min( @@ -466,7 +465,7 @@ lnurlServer.bindToHook( currency: receiverAccount.user.currency, confirmed: true, received: true, - network: "COINOS", + network: "COINOS" }, { transaction } ); @@ -483,7 +482,7 @@ lnurlServer.bindToHook( currency: user.currency, confirmed: true, network: "lightning", - fee_payment_id, + fee_payment_id }, { transaction } ); @@ -492,10 +491,10 @@ lnurlServer.bindToHook( try { let { payments } = await ln.getPayments({ lnd, - limit: 5, + limit: 5 }); - let p = payments.find((p) => p.request === pr); + let p = payments.find(p => p.request === pr); if (p) { l("found payment", pr); payment.fee = p.fee; @@ -539,28 +538,28 @@ lnurlServer.bindToHook( } ); -lnurlServer.bindToHook("login", async (key) => { +lnurlServer.bindToHook("login", async key => { try { if (!key) throw new Error("login key not defined"); const exists = await db.Key.findOne({ where: { hex: key }, - include: [{ model: db.User, as: "user" }], + include: [{ model: db.User, as: "user" }] }); let user; if (logins[key] && logins[key] !== "undefined") { const { username } = logins[key]; user = await db.User.findOne({ - where: { username }, + where: { username } }); if (user) { const [k, created] = await db.Key.findOrCreate({ where: { user_id: user.id, - hex: key, - }, + hex: key + } }); if (created) { @@ -571,7 +570,7 @@ lnurlServer.bindToHook("login", async (key) => { l("user not found"); user = await register({ username: key.substr(0, 8), - password: key, + password: key }); } } else if (exists) ({ user } = exists); diff --git a/routes/payments.js b/routes/payments.js index 6c489372..d1b2ba4c 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -64,7 +64,7 @@ app.post("/lightning/send", auth, lnRoutes.send); if (config.lnurl) { let { channelRequest } = await import("$routes/lightning/channelRequest"); - app.post("/lightning/channelRequest", channelRequest) + app.post("/lightning/channelRequest", channelRequest); } app.post("/bitcoin/broadcast", optionalAuth, btcRoutes.broadcast); diff --git a/routes/users.js b/routes/users.js index 3063758d..c270902c 100644 --- a/routes/users.js +++ b/routes/users.js @@ -29,20 +29,20 @@ app.get("/me", auth, async (req, res) => { let user = req.user.get({ plain: true }); let payments = await req.user.getPayments({ where: { - account_id: user.account_id, + account_id: user.account_id }, order: [["id", "DESC"]], limit: 12, include: [ { model: db.Account, - as: "account", + as: "account" }, { model: db.Payment, - as: "fee_payment", - }, - ], + as: "fee_payment" + } + ] }); user.accounts = await req.user.getAccounts(); user.payments = payments; @@ -56,11 +56,11 @@ app.get("/users/:username", async (req, res) => { const { username } = req.params; const user = await db.User.findOne({ - attributes: ["username", "banner", "profile"], + attributes: ["username", "banner", "profile", "address"], where: Sequelize.where( Sequelize.fn("lower", Sequelize.col("username")), username.toLowerCase() - ), + ) }); if (user) res.send(user); @@ -80,7 +80,7 @@ app.post("/register", async (req, res) => { app.post("/disable2fa", auth, async (req, res) => { let { user, - body: { token }, + body: { token } } = req; if ( @@ -120,7 +120,7 @@ app.post("/2fa", auth, async (req, res) => { app.get("/exists", async (req, res) => { let exists = await db.User.findOne({ - where: { username: req.query.username }, + where: { username: req.query.username } }); res.send(!!exists); @@ -142,11 +142,11 @@ app.post("/user", auth, async (req, res) => { tokens, twofa, unit, - username, + username } = req.body; let exists = await db.User.findOne({ - where: { username }, + where: { username } }); let token; @@ -161,7 +161,7 @@ app.post("/user", auth, async (req, res) => { token = jwt.sign({ username }, config.jwt); res.cookie("token", token, { - expires: new Date(Date.now() + 432000000), + expires: new Date(Date.now() + 432000000) }); } @@ -193,7 +193,7 @@ app.post("/keys", auth, async (req, res) => { const { key: hex } = req.body; const key = await db.Key.create({ user_id: req.user.id, - hex, + hex }); emit(req.user.username, "key", key); res.send(key); @@ -205,8 +205,8 @@ app.post("/keys/delete", auth, async (req, res) => { await db.Key.findOne({ where: { user_id: req.user.id, - hex, - }, + hex + } }) ).destroy(); }); @@ -222,12 +222,12 @@ app.post("/updateSeeds", auth, async (req, res) => { await db.Account.update( { seed }, { - where: { id, user_id: user.id }, + where: { id, user_id: user.id } } ); const account = await db.Account.findOne({ - where: { id }, + where: { id } }); emit(user.username, "account", account); @@ -244,8 +244,16 @@ app.post("/accounts/delete", auth, async (req, res) => { }); app.post("/accounts", auth, async (req, res) => { - const { name, seed, pubkey, ticker, precision, path, privkey, network } = - req.body; + const { + name, + seed, + pubkey, + ticker, + precision, + path, + privkey, + network + } = req.body; const { user } = req; let account = await db.Account.create({ @@ -260,7 +268,7 @@ app.post("/accounts", auth, async (req, res) => { privkey, seed, path, - network, + network }); emit(user.username, "account", account); @@ -346,14 +354,14 @@ app.post("/logout", optionalAuth, async (req, res) => { if (username) { l("logging out", username); let i = req.user.subscriptions.findIndex( - (s) => JSON.stringify(s) === subscription + s => JSON.stringify(s) === subscription ); if (i > -1) { req.user.subscriptions.splice(i, 1); } await req.user.save(); Object.keys(logins).map( - (k) => logins[k]["username"] === username && delete logins[k] + k => logins[k]["username"] === username && delete logins[k] ); } @@ -373,15 +381,15 @@ app.post("/account", auth, async (req, res) => { privkey, path, hide, - index, + index } = req.body; try { - await db.transaction(async (transaction) => { + await db.transaction(async transaction => { let account = await db.Account.findOne({ where: { id, user_id: user.id }, lock: transaction.LOCK.UPDATE, - transaction, + transaction }); let params = { @@ -394,14 +402,14 @@ app.post("/account", auth, async (req, res) => { path, hide, index, - privkey, + privkey }; if (!account || (account.pubkey && !pubkey)) delete params.pubkey; await db.Account.update(params, { where: { id, user_id: user.id }, - transaction, + transaction }); await account.reload({ transaction }); @@ -420,7 +428,7 @@ app.post("/shiftAccount", auth, async (req, res) => { try { const account = await db.Account.findOne({ - where: { id }, + where: { id } }); if (account.user_id !== user.id) @@ -430,14 +438,14 @@ app.post("/shiftAccount", auth, async (req, res) => { await user.save(); let payments = await db.Payment.findAll({ where: { - account_id: id, + account_id: id }, order: [["id", "DESC"]], limit: 12, include: { model: db.Account, - as: "account", - }, + as: "account" + } }); user = user.get({ plain: true }); @@ -454,18 +462,16 @@ app.post("/shiftAccount", auth, async (req, res) => { } }); -app.get("/vapidPublicKey", function (req, res) { +app.get("/vapidPublicKey", function(req, res) { res.send(config.vapid.publicKey); }); -app.post("/subscribe", auth, async function (req, res) { +app.post("/subscribe", auth, async function(req, res) { let { subscriptions } = req.user; let { subscription } = req.body; if (!subscriptions) subscriptions = []; if ( - !subscriptions.find( - (s) => JSON.stringify(s) === JSON.stringify(subscription) - ) + !subscriptions.find(s => JSON.stringify(s) === JSON.stringify(subscription)) ) subscriptions.push(subscription); req.user.subscriptions = subscriptions; @@ -475,10 +481,10 @@ app.post("/subscribe", auth, async function (req, res) { }); let redeeming = {}; -app.post("/redeem", optionalAuth, async function (req, res) { +app.post("/redeem", optionalAuth, async function(req, res) { const { redeemcode } = req.body; try { - await db.transaction(async (transaction) => { + await db.transaction(async transaction => { if (redeeming[redeemcode]) fail("redemption in progress"); redeeming[redeemcode] = true; if (!redeemcode) fail("no code provided"); @@ -487,14 +493,14 @@ app.post("/redeem", optionalAuth, async function (req, res) { const source = await db.Payment.findOne({ where: { - redeemcode: req.body.redeemcode, + redeemcode: req.body.redeemcode }, include: { model: db.Account, - as: "account", + as: "account" }, lock: transaction.LOCK.UPDATE, - transaction, + transaction }); l("redeeming", redeemcode); @@ -511,7 +517,7 @@ app.post("/redeem", optionalAuth, async function (req, res) { user = await register( { username: redeemcode.substr(0, 8), - password: "", + password: "" }, ip, false @@ -520,7 +526,7 @@ app.post("/redeem", optionalAuth, async function (req, res) { let payload = { username: user.username }; let token = jwt.sign(payload, config.jwt); res.cookie("token", token, { - expires: new Date(Date.now() + 432000000), + expires: new Date(Date.now() + 432000000) }); delete redeeming[redeemcode]; @@ -545,7 +551,7 @@ app.post("/redeem", optionalAuth, async function (req, res) { confirmed, network, received: true, - fee, + fee }, { transaction } ); @@ -568,14 +574,14 @@ app.post("/redeem", optionalAuth, async function (req, res) { } }); -app.post("/checkRedeemCode", auth, async function (req, res) { +app.post("/checkRedeemCode", auth, async function(req, res) { const { redeemcode } = req.body; const payment = await db.Payment.findOne({ where: { redeemcode } }); res.send(payment); }); -app.post("/password", auth, async function (req, res) { +app.post("/password", auth, async function(req, res) { const { user } = req; const { password } = req.body; @@ -583,7 +589,7 @@ app.post("/password", auth, async function (req, res) { res.send(await bcrypt.compare(password, user.password)); }); -app.get("/isInternal", auth, async function (req, res) { +app.get("/isInternal", auth, async function(req, res) { let { user } = req; let { address } = req.query; if (!address) throw new Error("Address not provided"); @@ -593,8 +599,8 @@ app.get("/isInternal", auth, async function (req, res) { include: { attributes: ["username"], model: db.User, - as: "user", - }, + as: "user" + } }); if (invoice) { @@ -613,21 +619,21 @@ app.get("/isInternal", auth, async function (req, res) { res.send(false); }); -app.get("/invoices", auth, async function (req, res) { +app.get("/invoices", auth, async function(req, res) { let invoices = await db.Invoice.findAll({ - where: { user_id: req.user.id }, + where: { user_id: req.user.id } }); res.send(invoices); }); -app.post("/signMessage", auth, async function (req, res) { +app.post("/signMessage", auth, async function(req, res) { let { address, message } = req.body; let invoices = await db.Invoice.findAll({ - where: { user_id: req.user.id }, + where: { user_id: req.user.id } }); - if (invoices.find((i) => i.address === address)) { + if (invoices.find(i => i.address === address)) { if (config.bitcoin.walletpass) await bc.walletPassphrase(config.bitcoin.walletpass, 300); return res.send(await bc.signMessage(address, message)); diff --git a/sampleconfig/lnurl.js b/sampleconfig/lnurl.js index 6f358983..aeb1dc32 100644 --- a/sampleconfig/lnurl.js +++ b/sampleconfig/lnurl.js @@ -20,10 +20,7 @@ export default { config: { hostname: "lnd:9735", cert: { - data: fs.readFileSync( - "/app/config/lnd/tls.cert", - "utf8" - ) + data: fs.readFileSync("/app/config/lnd/tls.cert", "utf8") }, macaroon: { data: @@ -31,16 +28,16 @@ export default { } } }, - store: { - backend: 'knex', - config: { - client: 'mysql', - connection: { - host: 'maria', - user: 'root', - password: 'password', - database: 'coinos', - }, - }, - }, + store: { + backend: "knex", + config: { + client: "mysql", + connection: { + host: "maria", + user: "root", + password: "password", + database: "coinos" + } + } + } }; |
