Compare commits
10 Commits
master
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80b9c29cb1 | ||
|
|
c156852cb2 | ||
|
|
4aec075855 | ||
|
|
843755fc00 | ||
|
|
d17d475dba | ||
|
|
7c13beea0a | ||
|
|
69f87fad35 | ||
|
|
e0be599146 | ||
|
|
01746ec98d | ||
|
|
4b28c16996 |
@@ -21,13 +21,13 @@
|
||||
|
||||
<!-- One Sky IT site custom Cascading Style Sheets (CSS) -->
|
||||
<link rel="stylesheet" href="http://dev.oneskyit.local:5000/static/css/aether_variables.css">
|
||||
<link rel="stylesheet" href="http://dev.oneskyit.local:5000/static/css/aether_utilities.css">
|
||||
<link rel="stylesheet" href="http://dev.oneskyit.local:5000/static/svelte/build/aether_utilities.css">
|
||||
<link rel="stylesheet" href="http://dev.oneskyit.local:5000/static/css/aether_system.css">
|
||||
<!-- <link rel="stylesheet" href="svelte/build/aether_layout.css"> -->
|
||||
<!-- <link rel="stylesheet" href="css/aether_layout_flow.css"> -->
|
||||
<!-- <link rel="stylesheet" href="css/aether_layout_grid.css"> -->
|
||||
<link rel="stylesheet" href="http://dev.oneskyit.local:5000/static/css/aether_modules_core.css">
|
||||
<link rel="stylesheet" href="http://dev.oneskyit.local:5000/static/css/aether_modules_other.css">
|
||||
<link rel="stylesheet" href="http://dev.oneskyit.local:5000/static/svelte/build/aether_modules_core.css">
|
||||
<!-- <link rel="stylesheet" href="http://dev.oneskyit.local:5000/static/svelte/build/aether_modules_other.css"> -->
|
||||
|
||||
<link href="http://dev.oneskyit.local:5000/static/svelte/build/bundle.css" rel="stylesheet">
|
||||
<link href="http://dev.oneskyit.local:5000/static/svelte/build/reloading.css" rel="stylesheet">
|
||||
@@ -35,7 +35,7 @@
|
||||
<link href="http://dev.oneskyit.local:5000/static/css/base_style_grid_layout_v3.css" rel="stylesheet">
|
||||
<link href="http://dev.oneskyit.local:5000/static/css/base_style_grid_theme_v3.css" rel="stylesheet">
|
||||
|
||||
<link href="http://dev.oneskyit.local:5000/event/assets/css/event_launcher.css" rel="stylesheet">
|
||||
<link href="http://dev.oneskyit.local:5000/static/svelte/build/event_launcher.css" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="css/aether_native_app_v3.css">
|
||||
|
||||
@@ -57,9 +57,10 @@
|
||||
<script src="https://static.oneskyit.com/js/utilities.js"></script>
|
||||
<!-- <script src="js/app_idb.js"></script> -->
|
||||
|
||||
<script>const app = require('./js/aether_native_app_v3');</script>
|
||||
<script>
|
||||
const app = require('./js/aether_native_app_v3');
|
||||
let app_config = app.load_config();
|
||||
console.log(app_config);
|
||||
|
||||
const flask_env = 'development'; // 'development', 'production'
|
||||
const env = 'development'; // 'development', 'production'
|
||||
@@ -76,13 +77,37 @@
|
||||
const page_for = { 'event': event_id, 'event_device': event_device_id, 'event_location': event_location_id }; // Simple key value like object
|
||||
console.log(page_for);
|
||||
|
||||
const host_file_cache_path = 'file_cache'; // app_config.host_file_cache_path; // 'file_cache/'
|
||||
console.log(host_file_cache_path);
|
||||
const host_file_temp_path = 'temp' // app_config.host_file_temp_path; // 'temp/'
|
||||
console.log(host_file_temp_path);
|
||||
const host_file_cache_path = app_config.host_file_cache_path; // 'file_cache/'
|
||||
// console.log(host_file_cache_path);
|
||||
const host_file_temp_path = app_config.host_file_temp_path; // 'temp/'
|
||||
// console.log(host_file_temp_path);
|
||||
|
||||
let idb_name = app_config.idb_name;
|
||||
|
||||
// BEGIN: API section
|
||||
|
||||
const access_control_allow_origin = app_config.access_control_allow_origin;
|
||||
const api_secret_key = app_config.api_secret_key;
|
||||
console.log(api_secret_key);
|
||||
let api_temporary_token = null;
|
||||
|
||||
let api_base_url = null;
|
||||
|
||||
if (app_config.use_local_api) {
|
||||
api_base_url = app_config.api_local_base_url; // 'http://api.localhost:5001'
|
||||
} else {
|
||||
api_base_url = app_config.api_remote_base_url; // 'https://api.oneskyit.com'
|
||||
}
|
||||
|
||||
/* ***** **** *** ** * ### * ** *** **** ***** */
|
||||
|
||||
let app_online = false;
|
||||
//let app_use_cached_data = true;
|
||||
window.addEventListener('online', app.currently_online);
|
||||
window.addEventListener('offline', app.currently_offline);
|
||||
|
||||
/* ***** **** *** ** * ### * ** *** **** ***** */
|
||||
|
||||
</script>
|
||||
|
||||
<!-- <script defer src="svelte/build/bundle.js" crossorigin></script> -->
|
||||
@@ -120,29 +145,9 @@
|
||||
<script>
|
||||
/* ***** **** *** ** * ### * ** *** **** ***** */
|
||||
|
||||
// BEGIN: API section
|
||||
|
||||
const access_control_allow_origin = app_config.access_control_allow_origin;
|
||||
const api_secret_key = app_config.api_secret_key;
|
||||
console.log(api_secret_key);
|
||||
let api_temporary_token = null;
|
||||
|
||||
let api_base_url = null;
|
||||
|
||||
if (app_config.use_local_api) {
|
||||
api_base_url = app_config.api_local_base_url; // 'http://api.localhost:5001'
|
||||
} else {
|
||||
api_base_url = app_config.api_remote_base_url; // 'https://api.oneskyit.com'
|
||||
}
|
||||
|
||||
/* ***** **** *** ** * ### * ** *** **** ***** */
|
||||
|
||||
let app_online = false;
|
||||
//let app_use_cached_data = true;
|
||||
window.addEventListener('online', app.currently_online);
|
||||
window.addEventListener('offline', app.currently_offline);
|
||||
|
||||
/* ***** **** *** ** * ### * ** *** **** ***** */
|
||||
|
||||
// BEGIN: Load IDB section
|
||||
// let idb_name = app_config.idb_name;
|
||||
|
||||
@@ -4,22 +4,30 @@ const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { ipcRenderer } = require('electron');
|
||||
|
||||
let home_directory = require('os').homedir();
|
||||
console.log('Home: '+home_directory);
|
||||
|
||||
let tmp_directory = require('os').tmpdir();
|
||||
console.log('Temporary: '+tmp_directory);
|
||||
|
||||
let config = null;
|
||||
|
||||
exports.load_config = function () {
|
||||
console.log('*** Electron framework: load_config() ***');
|
||||
console.log('CWD: '+process.cwd());
|
||||
|
||||
let home_directory = require('os').homedir();
|
||||
console.log('Home: '+home_directory);
|
||||
// let home_directory = require('os').homedir();
|
||||
// console.log('Home: '+home_directory);
|
||||
|
||||
let tmp_directory = require('os').tmpdir();
|
||||
console.log('Temporary: '+tmp_directory);
|
||||
// let tmp_directory = require('os').tmpdir();
|
||||
// console.log('Temporary: '+tmp_directory);
|
||||
|
||||
let config = null;
|
||||
// let config = null;
|
||||
let config_directory = null;
|
||||
let default_config_path = path.join(process.cwd(),'config.json.default');
|
||||
let config_path = null;
|
||||
|
||||
// Set the config path for macOS or Linux
|
||||
if (os.platform == 'darwin') {
|
||||
config_directory = path.join(home_directory, 'Library/Application Support/OSIT');
|
||||
console.log('macOS config directory: '+config_directory);
|
||||
@@ -28,6 +36,7 @@ exports.load_config = function () {
|
||||
console.log('Linux config directory: '+config_directory);
|
||||
}
|
||||
|
||||
// Look for the config file and copy the default if not found.
|
||||
if (fs.existsSync(config_directory)) {
|
||||
console.log('Config: '+config_directory);
|
||||
config_path = path.join(config_directory, 'config.json');
|
||||
@@ -41,6 +50,7 @@ exports.load_config = function () {
|
||||
console.log('Default config file copied: '+config_directory);
|
||||
}
|
||||
|
||||
// Attempt to open the config file. The preferred location is based on the OS's config directory.
|
||||
if (fs.existsSync(config_path)) {
|
||||
console.log('Config path: '+config_path);
|
||||
console.log('Config file (config.json) found under '+config_directory+'.');
|
||||
@@ -66,6 +76,21 @@ exports.load_config = function () {
|
||||
} else {
|
||||
//close();
|
||||
}
|
||||
|
||||
config.host_file_cache_path = config.host_file_cache_path.replace('[home]', home_directory);
|
||||
config.host_file_cache_path = config.host_file_cache_path.replace('[tmp]', tmp_directory);
|
||||
console.log(config.host_file_cache_path);
|
||||
|
||||
config.host_file_temp_path = config.host_file_temp_path.replace('[home]', home_directory);
|
||||
config.host_file_temp_path = config.host_file_temp_path.replace('[tmp]', tmp_directory);
|
||||
console.log(config.host_file_temp_path);
|
||||
|
||||
let import_config_to_ipc_result = ipcRenderer.invoke('import_config', config).then((result) => {
|
||||
console.log('IPC import config finished');
|
||||
console.log(result);
|
||||
return true;
|
||||
})
|
||||
|
||||
//console.log(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
52
config.json
52
config.json
@@ -7,29 +7,15 @@
|
||||
"event_presentation_id": null,
|
||||
"event_presenter_id": null,
|
||||
"event_file_id": null,
|
||||
"api_auth_loop_interval": 100,
|
||||
"api_token_update_loop_interval": 120000,
|
||||
"open_tables_loop_interval": 10,
|
||||
"update_idb_loop_interval": 10,
|
||||
"idb_to_launcher_loop_interval": 250,
|
||||
"update_render_loop_interval": 1000,
|
||||
"check_file_cache_loop_interval": 250,
|
||||
|
||||
"api_secret_key": "dFP6J9DVj9hUgIMn-fNIqg",
|
||||
"use_local_api": true,
|
||||
"use_local_db": false,
|
||||
"api_remote_base_url": "https://dev-fastapi.oneskyit.com",
|
||||
"api_local_base_url": "http://dev-fastapi.oneskyit.local:5005",
|
||||
"access_control_allow_origin": "*",
|
||||
"remote_db_server": "db.oneskyit.com",
|
||||
"remote_db_port": "3306",
|
||||
"remote_db_name": "onesky_ams_test",
|
||||
"remote_db_username": "username_here",
|
||||
"remote_db_password": "password_here",
|
||||
"local_db_server": "db.oneskyit.local",
|
||||
"local_db_port": "3306",
|
||||
"local_db_name": "onesky_ams_test",
|
||||
"local_db_username": "username_here",
|
||||
"local_db_password": "password_here",
|
||||
|
||||
"use_local_api": true,
|
||||
"use_local_db": false,
|
||||
|
||||
"idb_name": "osit",
|
||||
"idb_event_check_period": 120000,
|
||||
"idb_event_location_check_period": 90000,
|
||||
@@ -37,9 +23,31 @@
|
||||
"idb_event_presentation_check_period": 90000,
|
||||
"idb_event_presenter_check_period": 60000,
|
||||
"idb_event_file_check_period": 30000,
|
||||
"host_file_cache_path": "file_cache",
|
||||
|
||||
"host_file_cache_path": "[home]/tmp/OSIT/file_cache",
|
||||
"host_file_cache_check_period": 30000,
|
||||
"host_file_temp_path": "temp",
|
||||
"host_file_temp_path": "[home]/tmp/OSIT/temp",
|
||||
|
||||
"main_loop_interval": 2000,
|
||||
"api_token_loop_interval": 1000,
|
||||
"api_update_period": 90000,
|
||||
"api_auth_loop_interval": 100,
|
||||
"api_token_update_loop_interval": 120000,
|
||||
|
||||
"open_tables_loop_interval": 10,
|
||||
"update_idb_loop_interval": 10,
|
||||
"idb_to_launcher_loop_interval": 250,
|
||||
"update_render_loop_interval": 1000,
|
||||
"check_file_cache_loop_interval": 250,
|
||||
|
||||
"display_menu_session_times": true,
|
||||
"display_session_codes": true,
|
||||
"display_session_badges": true,
|
||||
"display_presentation_codes": true,
|
||||
"display_presentation_badges": true,
|
||||
"display_presenter_codes": true,
|
||||
"display_presenter_badges": true,
|
||||
|
||||
"display_arrangement": "mirror_and_extend",
|
||||
"display_builtin_resolution": "",
|
||||
"display_builtin_refresh": "",
|
||||
@@ -47,8 +55,10 @@
|
||||
"display_external_resolution": "",
|
||||
"display_external_refresh": "",
|
||||
"display_external_rotation": "",
|
||||
|
||||
"audio_out_volume": null,
|
||||
"audio_in_volume": null,
|
||||
|
||||
"recording_fps": 30,
|
||||
"recording_show_cursor": true,
|
||||
"recording_highlight_clicks": false,
|
||||
|
||||
@@ -1,39 +1,42 @@
|
||||
{
|
||||
"account_id": "_XY7DXtc9MY",
|
||||
"event_id": "pjrcghqwert",
|
||||
"event_location_id": "LUNt2zdMKCUNb9VReMZu8A",
|
||||
"main_loop_interval": 2000,
|
||||
"api_token_loop_interval": 1000,
|
||||
"api_update_period": 90000,
|
||||
"api_secret_key": "dFP6J9DVj9hUgIMn-fNIqg",
|
||||
"use_local_api": true,
|
||||
"use_local_db": false,
|
||||
"account_id": "",
|
||||
"event_id": "",
|
||||
"event_device_id": "",
|
||||
"event_location_id": "",
|
||||
"event_session_id": "",
|
||||
|
||||
"api_secret_key": "XXXXXX",
|
||||
"api_remote_base_url": "https://dev-fastapi.oneskyit.com",
|
||||
"api_local_base_url": "http://dev-fastapi.oneskyit.local:5005",
|
||||
"access_control_allow_origin": "*",
|
||||
"remote_db_server": "linode.oneskyit.com",
|
||||
"remote_db_port": "3306",
|
||||
"remote_db_name": "onesky_ams_test",
|
||||
"remote_db_username": "username_here",
|
||||
"remote_db_password": "password_here",
|
||||
"local_db_server": "db.oneskyit.local",
|
||||
"local_db_port": "3306",
|
||||
"local_db_name": "onesky_ams_test",
|
||||
"local_db_username": "username_here",
|
||||
"local_db_password": "password_here",
|
||||
"update_idb_loop_interval": 1000,
|
||||
|
||||
"use_local_api": true,
|
||||
"use_local_db": false,
|
||||
|
||||
"idb_name": "osit",
|
||||
"idb_check_period": 30000,
|
||||
"idb_event_check_period": 120000,
|
||||
"idb_event_location_check_period": 90000,
|
||||
"idb_event_session_check_period": 60000,
|
||||
"idb_event_presentation_check_period": 60000,
|
||||
"idb_event_session_check_period": 90000,
|
||||
"idb_event_presentation_check_period": 90000,
|
||||
"idb_event_presenter_check_period": 60000,
|
||||
"idb_event_file_check_period": 60000,
|
||||
"check_file_cache_loop_interval": 250,
|
||||
"host_file_cache_path": "file_cache",
|
||||
"idb_event_file_check_period": 30000,
|
||||
|
||||
"host_file_cache_path": "[home]/OSIT/file_cache",
|
||||
"host_file_cache_check_period": 30000,
|
||||
"host_file_temp_path": "[home]/OSIT/temp",
|
||||
|
||||
"main_loop_interval": 2000,
|
||||
"api_token_loop_interval": 1000,
|
||||
"api_update_period": 90000,
|
||||
"api_auth_loop_interval": 100,
|
||||
"api_token_update_loop_interval": 120000,
|
||||
|
||||
"open_tables_loop_interval": 10,
|
||||
"update_idb_loop_interval": 10,
|
||||
"idb_to_launcher_loop_interval": 250,
|
||||
"update_render_loop_interval": 1000,
|
||||
"check_file_cache_loop_interval": 250,
|
||||
|
||||
"display_menu_session_times": true,
|
||||
"display_session_codes": true,
|
||||
"display_session_badges": true,
|
||||
@@ -41,6 +44,7 @@
|
||||
"display_presentation_badges": true,
|
||||
"display_presenter_codes": true,
|
||||
"display_presenter_badges": true,
|
||||
|
||||
"display_arrangement": "mirror_and_extend",
|
||||
"display_builtin_resolution": "",
|
||||
"display_builtin_refresh": "",
|
||||
@@ -48,18 +52,20 @@
|
||||
"display_external_resolution": "",
|
||||
"display_external_refresh": "",
|
||||
"display_external_rotation": "",
|
||||
|
||||
"audio_out_volume": null,
|
||||
"audio_in_volume": null,
|
||||
"fps": 30,
|
||||
"show_cursor": true,
|
||||
"highlight_clicks": false,
|
||||
"screen_id": null,
|
||||
"audio_device_id": null,
|
||||
|
||||
"recording_fps": 30,
|
||||
"recording_show_cursor": true,
|
||||
"recording_highlight_clicks": false,
|
||||
"recording_screen_id": null,
|
||||
"recording_audio_device_id": null,
|
||||
"known_builtin_screen_ids": [69732032, 69733952, 69733248],
|
||||
"known_builtin_audio_device_ids": [ "AppleHDAEngineInput:1B,0,1,0:1", "BuiltInMicrophoneDevice" ],
|
||||
"video_codec": "h264",
|
||||
"recordings_path": "[home]/recordings",
|
||||
"base_filename": "recording",
|
||||
"recording_video_codec": "h264",
|
||||
"recording_path": "[home]/recordings",
|
||||
"recording_base_filename": "recording",
|
||||
"aperture_bin_path": null,
|
||||
"recording_start_datetime": "2019-10-12 01:01:01Z",
|
||||
"recording_stop_datetime": "2019-10-31 23:59:59Z",
|
||||
|
||||
55
index.js
55
index.js
@@ -11,6 +11,16 @@ const process = require('process');
|
||||
//const url = require('url');
|
||||
// const usb = require('usb') // Compiled with an old version of Node.js
|
||||
|
||||
let home_directory = require('os').homedir();
|
||||
console.log('Home: '+home_directory);
|
||||
|
||||
let tmp_directory = require('os').tmpdir();
|
||||
console.log('Temporary: '+tmp_directory);
|
||||
|
||||
let config = null;
|
||||
let host_file_cache_path = null;
|
||||
let host_file_temp_path = null;
|
||||
|
||||
console.log(os.type());
|
||||
console.log(process.getSystemVersion());
|
||||
|
||||
@@ -97,6 +107,37 @@ app.on('activate', () => {
|
||||
})
|
||||
|
||||
|
||||
// Import config data
|
||||
// Updated 2022-04-16
|
||||
ipcMain.handle('import_config', async (event, config_data) => {
|
||||
console.log('*** Electron IPC Main: import_config() ***');
|
||||
// console.log('ipcMain on download_file: api_base_url='+api_base_url+' | api_temporary_token='+api_temporary_token);
|
||||
console.log('ipcMain on import_config:');
|
||||
console.log(config_data);
|
||||
|
||||
config = config_data;
|
||||
|
||||
host_file_cache_path = config.host_file_cache_path;
|
||||
host_file_temp_path = config.host_file_temp_path;
|
||||
|
||||
if (fs.existsSync(host_file_cache_path)) {
|
||||
console.log('Host file cache path exists: '+host_file_cache_path);
|
||||
} else {
|
||||
fs.mkdirSync(host_file_cache_path, true);
|
||||
console.log('Host file cache path created: '+host_file_cache_path);
|
||||
}
|
||||
|
||||
if (fs.existsSync(host_file_temp_path)) {
|
||||
console.log('Host file temp path exists: '+host_file_temp_path);
|
||||
} else {
|
||||
fs.mkdirSync(host_file_temp_path, true);
|
||||
console.log('Host file temp path created: '+host_file_temp_path);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
// Download file to path
|
||||
// full_save_path should be the full path that includes the filename
|
||||
// Updated 2022-03-09
|
||||
@@ -122,10 +163,10 @@ async function download_file(api_base_url, api_endpoint, full_save_path) {
|
||||
console.log('*** node.js: download_file() ***');
|
||||
|
||||
axios.defaults.baseURL = api_base_url;
|
||||
axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*'; // app_config.access_control_allow_origin;
|
||||
axios.defaults.headers.common['Access-Control-Allow-Origin'] = config.access_control_allow_origin; // '*'; // app_config.access_control_allow_origin;
|
||||
axios.defaults.headers.common['content-type'] = 'application/json';
|
||||
axios.defaults.headers.common['x-aether-api-key'] = 'dFP6J9DVj9hUgIMn-fNIqg'; // api_secret_key;
|
||||
axios.defaults.headers.common['x-account-id'] = '_XY7DXtc9MY'; // account_id;
|
||||
axios.defaults.headers.common['x-aether-api-key'] = config.api_secret_key; // 'dFP6J9DVj9hUgIMn-fNIqg'; // api_secret_key;
|
||||
axios.defaults.headers.common['x-account-id'] = config.account_id; // '_XY7DXtc9MY'; // account_id;
|
||||
|
||||
const url = api_endpoint;
|
||||
|
||||
@@ -188,14 +229,18 @@ ipcMain.handle('open_hash_file_to_temp', async (event, host_file_cache_path, has
|
||||
console.log('ipcMain on open_hash_file_to_temp');
|
||||
console.log(`ipcMain open hash file from temp directory: ${host_file_cache_path} -> ${host_file_temp_path}/${filename}`);
|
||||
|
||||
let cache_file_path = path.join(process.cwd(), host_file_cache_path);
|
||||
// NOTE: This may be needed later? Uncomment if paths are relative to working directory.
|
||||
// let cache_file_path = path.join(process.cwd(), host_file_cache_path);
|
||||
let cache_file_path = host_file_cache_path;
|
||||
console.log(cache_file_path);
|
||||
|
||||
let hash_filename = hash+'.file';
|
||||
let full_cache_file_path = path.join(cache_file_path, hash_filename);
|
||||
console.log(full_cache_file_path);
|
||||
|
||||
open_temp_file_path = path.join(process.cwd(), host_file_temp_path, filename); // 'temp/'
|
||||
// NOTE: This may be needed later? Uncomment if paths are relative to working directory.
|
||||
// open_temp_file_path = path.join(process.cwd(), host_file_temp_path, filename); // 'temp/'
|
||||
open_temp_file_path = path.join(host_file_temp_path, filename); // 'temp/'
|
||||
console.log(open_temp_file_path);
|
||||
|
||||
if (fs.existsSync(open_temp_file_path)) {
|
||||
|
||||
2264
package-lock.json
generated
2264
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "onesky_native",
|
||||
"version": "2.0.0",
|
||||
"description": "One Sky Native App",
|
||||
"name": "aether_app_native",
|
||||
"productName": "Aether App",
|
||||
"version": "3.0.0",
|
||||
"description": "One Sky IT's Native Aether App",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
@@ -12,12 +13,15 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"axios": "^0.26.0",
|
||||
"electron": "^17.1.0",
|
||||
"fs": "0.0.1-security",
|
||||
"os": "^0.1.1",
|
||||
"path": "^0.12.7",
|
||||
"request": "^2.88.2",
|
||||
"screen": "^0.2.10",
|
||||
"usb": "^1.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^17.4.0",
|
||||
"electron-packager": "^15.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user