soselo/views/instance.php

627 lines
24 KiB
PHP

<div class="hmax">
<div id="tabs"></div>
<span id="tabs-item" data-id="{id}">
<a href="javascript:window.view.instance.load_content('{id}',true)">
<div class="tab-content">
<i class="fa fa-{icon} fa-fw"></i>
<span>{title}</span>
</div>
</a>
</span>
<div id="content">
<div id="container"></div>
</div>
</div>
<script>
window.view.instance = {
get_config: function() {
var config = {};
const hdict = window.vars.current_instance.config.trim().split('\n');
for (var i = 0; i < hdict.length; i++) {
const k = hdict[i].substr(0, hdict[i].indexOf('=')).trim();
const v = hdict[i].substr(hdict[i].indexOf('=')+1).trim();
config[k] = v;
}
return config;
},
show_config: function() {
window.location.hash = window.location.hash.replace('#instance/','#instance_config/');
},
acct_fill: function(acct) {
if (!acct.includes('@')) {
const hargs = get_hash_arguments();
return acct+'@'+hargs.instance;
}
return acct;
},
html_add_search_spans: function(html, search) {
search = search.trim();
if (search.startsWith('expr:'))
{
var t = remove_accents(html);
t = t.replace(/[^a-zA-Z0-9]/g, ' ');
t = normalize_word_sound(t.toLowerCase());
search = search.substr(5).trim();
var sxs = search
.replaceAll('\n', ' ')
.replaceAll('(', '')
.replaceAll(')','')
.replaceAll(/\s+/g, ' ')
.replaceAll('NOT', '!')
.split(/OR|AND/);
const regex_process = function(cnt, whole_word) {
if (cnt.trim() === '') return false;
whole_word = whole_word === undefined ? false : whole_word;
cnt = cnt.replace(/\s+/g, ' ').trim().replaceAll(' ', '.')
.replace(/\w/g, function(m) { return m+'+?\\s?'});
cnt = cnt.substr(0, cnt.length-3);
if (whole_word) cnt = '\\b'+cnt+'\\b';
t = t.replace(new RegExp(cnt, 'g'), function(m, st) {
var en = st + m.length;
const inj_st = '</S>';
const inj_en = '</E>';
html = insert_string(html, inj_st, st);
html = insert_string(html, inj_en, en + inj_st.length);
return inj_st + m + inj_en;
});
return true;
};
for (var i = 0; i < sxs.length; i++)
{
const sx = sxs[i].trim();
if (sx.startsWith('!'))
continue;
const selector = sx.substr(0, sx.indexOf(' ')).trim();
var content = sx.substr(sx.indexOf(' ')+1).trim();
content = normalize_for_search(content);
switch (selector)
{
case 'words':
case 'hasall':
case 'anyword':
case 'hasany':
const text_words = content.split(' ');
for (var j = 0; j < text_words.length; j++)
regex_process(text_words[j], true);
break;
case 'has':
case 'includes':
case 'contains':
case 'regex':
regex_process(content);
break;
}
}
html = html.replaceAll('</S>', '<span class="sr">');
html = html.replaceAll('</E>', '</span>');
return html;
}
if (search === '<empty>')
return html;
search = search.replaceAll('"', '');
return window.view.instance.html_add_search_spans(html, `expr: words "${search}"`);
},
do: {
users: {
trust_user: function(acct) {
acct = window.view.instance.acct_fill(acct);
if (!confirm('Are you sure you want to trust this user? It will NOT appear in any '+
'<filter results/timeline or screen> in all this web application!')) return false;
http.get(`api/v1/config/trusted_users/add?acct=${acct}`,
{}, function(js) {
if (js.ok) return toast.info(js.ok);
if (js.error) return toast.info(js.error);
});
return true;
},
hide_on_filters: function(acct, expires) {
const pname = window.view.instance.do.filter_users.get_current_filter().preset_name;
if (pname === undefined) return false;
const hargs = get_hash_arguments();
acct = window.view.instance.acct_fill(acct);
http.get(`api/v1/cache/put?keys=temp_hidden;`+
`hash:${hargs.software}${hargs.instance}${pname}; ${acct}`+
`&content=temp_hidden&expires=${expires}`,
{}, function(js) {
if (js.ok) return toast.info('User has been hidden from this filter for the specified time.');
});
return true;
},
suspend: function(_id) {
if (!confirm('Are you sure you want to suspend this user?')) return false;
const hargs = get_hash_arguments();
http.get(`api/v1/http/${hargs.software}/accounts/suspend?instance=${hargs.instance}&id=${_id}`,
{}, function(js) {
toast.info('User has been successfully suspended');
});
return true;
},
silence: function(_id) {
const hargs = get_hash_arguments();
http.get(`api/v1/http/${hargs.software}/accounts/silence?instance=${hargs.instance}&id=${_id}`,
{}, function(js) {
toast.info('User has been successfully silenced');
});
return true;
},
},
new_accounts: {
approve: function(_id) {
window.view.instance.do.new_accounts._perform('approve', _id);
},
reject: function(_id) {
window.view.instance.do.new_accounts._perform('reject', _id);
},
_perform: function(action, _id) {
const hargs = get_hash_arguments();
http.get(`api/v1/http/${hargs.software}/accounts/${action}/?instance=${hargs.instance}&id=${_id}`,
{}, function(js) {
window.view.instance.load_content('new-accounts');
});
},
},
filter_users: {
get_current_filter: function() {
var data = {};
if (E.element('#filters-current input[name=preset_id]').value !== '-1')
data.id = E.element('#filters-current input[name=preset_id]').value;
var preset = E.element('#filters-current input[name="preset_name"]').value.trim();
if (preset !== '' && preset.toLowerCase() !== 'undefined')
data.preset_name = E.element('#filters-current input[name="preset_name"]').value;
data.user_filter = E.element('#filters-current input[name=user_filter]:checked').value;
var prof_stype = E.element("#filters-current input[name=profile_search_type]:checked").value;
var profile = E.element("#filters-current textarea[name=profile]").value;
if (prof_stype === 'empty')
profile = '<empty>';
else if (prof_stype === 'expr')
profile = 'expr: '+profile;
data.profile = btoa(encodeURIComponent(profile));
var instances = E.element('#filters-current textarea[name=instances]').value.trim();
if (instances !== '') {
data.instances = instances;
data.user_filter = 'remote';
}
var languages = E.element('#filters-current textarea[name=languages]').value.trim();
if (languages !== '')
data.languages = languages;
const obj_noavatar = E.element('*[name=no_avatar]:checked');
if (obj_noavatar !== null)
data.no_avatar = '';
const obj_nostatuses = E.element('*[name=no_statuses]:checked');
if (obj_nostatuses !== null)
data.no_statuses = '';
const obj_nofollows = E.element('*[name=no_follows]:checked');
if (obj_nofollows !== null)
data.no_follows = '';
const obj_ismoved = E.element('*[name=is_moved]:checked');
if (obj_ismoved !== null)
data.is_moved = '';
var olderThan = E.element('#filters-current input[name=older_than_days]').value;
if (olderThan !== '') {
olderThan = Number.parseInt(olderThan);
if (olderThan > 0)
data.older_than_days = olderThan;
}
var newerThan = E.element('#filters-current input[name=newer_than_days]').value;
if (newerThan !== '') {
newerThan = Number.parseInt(newerThan);
if (newerThan > 0)
data.newer_than_days = newerThan;
}
var lastNActive = E.element('#filters-current input[name=last_n_active]').value;
if (lastNActive !== '') {
lastNActive = Number.parseInt(lastNActive);
if (lastNActive > 0)
data.last_n_active = lastNActive;
}
return data;
},
set_current_filter: function(data) {
const hargs = get_hash_arguments();
const _process = function(_d) {
var d = JSON.parse(JSON.stringify(_d));
if (d.id === undefined)
E.element('#filters-current input[name=preset_id]').value = -1;
else E.element('#filters-current input[name=preset_id]').value = d.id;
if (d.preset_name === undefined) {
d.preset_name = 'Undefined';
E.elemid('filter-current-name').innerText = '*New filter';
} else E.elemid('filter-current-name').innerText = d.preset_name;
E.element('#filters-current input[name="preset_name"]').value = d.preset_name;
if (d.user_filter === undefined) d.user_filter = 'local';
if (d.instances !== undefined && d.instances !== '')
d.user_filter = 'remote';
E.element('#filters-current input[name=user_filter][value='+d.user_filter+']').click();
if (d.profile === undefined) d.profile = '';
d.profile = decodeURIComponent(atob(d.profile));
if (d.profile === '<empty>')
E.element('#filters-current #profile-search-type-empty').click();
else if (d.profile.startsWith('expr:')) {
d.profile = d.profile.replace(/^expr:/,'').trim();
E.element('#filters-current #profile-search-type-expr').click();
E.element("#filters-current textarea[name=profile]").value = d.profile;
}
else {
E.element('#filters-current #profile-search-type-simple').click();
E.element("#filters-current textarea[name=profile]").value = d.profile;
}
E.element('#filters-current textarea[name=instances]').value = d.instances !== undefined ? d.instances : '';
E.element('#filters-current textarea[name=languages]').value = d.languages !== undefined ? d.languages : '';
E.elements('#filters-current input[type=checkbox]').forEach(function(it){ it.checked = false });
if (d.no_avatar !== undefined) E.element('#filters-current input[name=no_avatar]').click();
if (d.no_statuses !== undefined) E.element('#filters-current input[name=no_statuses]').click();
if (d.no_follows !== undefined) E.element('#filters-current input[name=no_follows]').click();
if (d.is_moved !== undefined) E.element('#filters-current input[name=is_moved]').click();
E.element('#filters-current input[name=older_than_days]').value = NaN;
E.element('#filters-current input[name=newer_than_days]').value = NaN;
if (d.older_than_days !== undefined)
E.element('#filters-current input[name=older_than_days]').value = Number.parseInt(d.older_than_days);
if (d.newer_than_days !== undefined)
E.element('#filters-current input[name=newer_than_days]').value = Number.parseInt(d.newer_than_days);
if (d.last_n_active !== undefined)
E.element('#filters-current input[name=last_n_active]').value = Number.parseInt(d.last_n_active);
};
if (typeof data === 'object')
_process(data);
else if (typeof data === 'string') {
for (var i = 0; i < window.vars.user_filters.length; i++) {
if (window.vars.user_filters[i].id === data) {
_process(window.vars.user_filters[i]);
http.get(`api/v1/config/filters/actions/get?instance=${hargs.instance}&type=users&id=${data}`,
{},function(js) {
E.template('filter-instance-action', function(TPL) {
var tpl = TPL;
tpl = tpl.replaceAll('{instance}', hargs.instance);
tpl = tpl.replaceAll('{id}', window.vars.user_filters[i].id);
return tpl;
});
if (js.action === null)
js.action = { name: 'none', interval: NaN, explain: '' };
E.element('#filter-instance-action select[name=instance_action_name]')
.value = js.action.name;
E.element('#filter-instance-action input[name=instance_action_interval]')
.value = js.action.interval;
E.element('#filter-instance-action textarea[name=instance_action_explain]')
.value = js.action.explain;
});
break;
}
}
}
},
save_filter_action: function(_id) {
const hargs = get_hash_arguments();
const v = E.element('#filter-instance-action select[name=instance_action_name]').value.trim();
var v2 = E.element('#filter-instance-action input[name=instance_action_interval]').value.trim();
v2 = Number.parseInt(v2) === NaN ? 0 : Number.parseInt(v2);
const v3 = E.element('#filter-instance-action textarea[name=instance_action_explain]').value.trim();
const payload = { interval: v2, explain: v3 };
http.post(`api/v1/config/filters/actions/put?instance=${hargs.instance}&type=users&id=${_id}&action=${v}`,
payload, function(js){ if (js.ok) toast.info(js.ok) });
},
delete_filter: function(_id) {
if (!confirm('Are you sure you want to delete this filter?'))
return;
http.post(`api/v1/config/filters/del?type=users`,
{ id: _id },function(js) {
if (js.ok !== undefined) {
window.view.instance.load_content('filter-users');
toast.info(js.ok);
} else toast.error('unknown error ocurred');
});
},
execute: function(page, items_per_page) {
const btn = E.elemid('btncollapse-filters-current');
if (btn.innerText.trim() === 'hide') btn.click();
window.scrollTo(0,0);
const data = window.view.instance.do.filter_users.get_current_filter();
delete data.id;
const hargs = get_hash_arguments();
var payload = data;
payload.instance = hargs.instance;
payload = JSON_to_URLEncoded(payload);
page = page === undefined ? 1 : page;
items_per_page = items_per_page === undefined ? 20 : items_per_page;
if (page === 'null') return;
page--; if (page < 0) page = 0;
var loader_msg = 'Loading query...';
if (data.user_filter === 'remote')
loader_msg = 'Loading query (this may take up to 10 minutes, depending on your instance users)...';
E.custom.loader.show(loader_msg, true);
http.get(`api/v1/database/${hargs.software}/accounts/search?${payload}&paging=${page},${items_per_page}`, data, function(js) {
if (js === undefined) return toast.error('Could not process the query result');
if (js.ok !== undefined) return toast.info(js.ok);
if (js.error !== undefined) return toast.error(js.error);
const filter = window.view.instance.do.filter_users.get_current_filter();
if (filter === undefined) return;
const filter_profile = decodeURIComponent(atob(filter.profile));
E.template('users-all', function(TPL) {
var html = '';
for (var i = 0; i < js['data'].length; i++) {
var tpl = TPL;
const it = js['data'][i];
tpl = tpl.replaceAll('{software}', hargs.software);
tpl = tpl.replaceAll('{id}', it.id);
tpl = tpl.replaceAll('{name}', html2text(it.name));
tpl = tpl.replaceAll('{acct}', html2text(it.acct));
if (it.avatar === null)
it.avatar = 'img/noavatar.png';
tpl = tpl.replaceAll('{avatar}', it.avatar);
tpl = tpl.replaceAll('{statuses}', it.statuses);
tpl = tpl.replaceAll('{following}', it.following);
tpl = tpl.replaceAll('{followers}', it.followers);
tpl = tpl.replaceAll('{disabledClass}', it.silenced === true ? 'disabled' : '');
tpl = tpl.replaceAll('{silencedClass}', it.silenced === true ? 'silenced' : '');
tpl = tpl.replaceAll('{disabledHTML}', it.silenced === true ? 'disabled="true"' : '');
tpl = tpl.replaceAll('{silencedText}', it.silenced === true ? 'Silenced' : 'Silence');
if (hargs.software === 'mastodon') {
const instance_url = window.view.instance.get_config().instance_url;
tpl = tpl.replaceAll('{accountAdminLink}', instance_url+'/admin/accounts/'+it.id);
if (![null, undefined].includes(it.fields)) {
var _fields = '<table class="fields"><tbody>';
for (var j = 0; j < it.fields.length; j++) {
var t = '<tr class="{verified}"><td>{name}</td><td>{value}</td>{verifiedColumn}</tr>';
t = t.replaceAll('{name}', window.view.instance.html_add_search_spans(
html2text(it.fields[j].name), filter_profile));
t = t.replaceAll('{value}', window.view.instance.html_add_search_spans(
html2text(it.fields[j].value), filter_profile));
t = t.replaceAll('{verified}', it.fields[j].verified_at !== undefined ? 'verified' : '');
t = t.replaceAll('{verifiedColumn}', it.fields[j].verified_at !== undefined ?
'<td title="verified"><i class="fa fa-check fa-fw"></i></td>' : '');
_fields += t;
}
_fields += '</tbody></table>';
tpl = tpl.replaceAll('{mastodon:fields}', _fields);
} else tpl = tpl.replaceAll('{mastodon:fields}', '');
}
tpl = tpl.replaceAll('{accountAdminLink}', 'javascript:void(0)');
tpl = tpl.replaceAll('{note}', it.note.trim() === '' ?
'&lt;empty&gt;' : window.view.instance.html_add_search_spans(
html2text(it.note), filter_profile));
html += tpl;
}
return html;
});
E.template('paging', function(TPL) {
var tpl = TPL;
if (js['paging']['total_pages'] === 0)
js['paging']['total_pages'] = 1;
page++;
var prevpage = page;
if (prevpage > 0) prevpage--;
else prevpage = 1;
var nextpage = page+1;
if (nextpage > js['paging']['total_pages'])
nextpage = js['paging']['total_pages'];
tpl = tpl.replaceAll('{current_page}', page);
tpl = tpl.replaceAll('{prev_page}', prevpage);
tpl = tpl.replaceAll('{next_page}', nextpage);
tpl = tpl.replaceAll('{items_per_page}', items_per_page);
tpl = tpl.replaceAll('{total_pages}', js['paging']['total_pages']);
tpl = tpl.replaceAll('{total_users}', js['total']);
return tpl+'<br>';
});
E.template('#paging.bottom', function(TPL) {
return E.elemid('paging').innerHTML;
});
}, 'users');
},
save_filter: function() {
const data = window.view.instance.do.filter_users.get_current_filter();
if (data.preset_name === undefined)
return toast.error("You must define a preset_name other than 'Undefined' or empty");
if (data.id === undefined)
data.id = uuidv4();
window.view.instance.do.filter_users.set_current_filter(data);
http.post('api/v1/config/filters/put?type=users', data, function(js) {
if (js.ok !== undefined)
window.view.instance.load.filter_users();
});
},
},
},
load: {
new_accounts: function() {
const hargs = get_hash_arguments();
E.http_template('instance/new-account', function(html) {
E.element('#window-instance #container').innerHTML = html;
http.get(`api/v1/database/${hargs.software}/get-pending-users/?instance=${hargs.instance}`,
{}, function(js) {
E.template('new-accounts', function(TPL) {
if ((js.count === undefined || js.account === null)
|| js.count === 0)
return 'There is not any pending accounts';
var tpl = TPL;
tpl = tpl.replaceAll('{count}', js.count);
tpl = tpl.replaceAll('{id}', js.account.id);
tpl = tpl.replaceAll('{text}', html2text(js.account.text));
tpl = tpl.replaceAll('{email}', html2text(js.account.email));
tpl = tpl.replaceAll('{username}', html2text(js.account.username));
tpl = tpl.replaceAll('{ip_address}', html2text(js.account.sign_up_ip));
return tpl;
});
});
});
},
filter_users: function() {
const hargs = get_hash_arguments();
E.http_template('instance/filter-users', function(html) {
html = html.replaceAll('{view.js}', 'window.view.instance.do.filter_users');
html = html.replaceAll('{do.js}', 'window.view.instance.do');
E.element('#window-instance #container').innerHTML = html;
E.elemid('profile-search-type-simple').onchange = function(e) {
if (e.target.checked) {
E.element('#filters-current textarea[name=profile]').setAttribute('placeholder', 'Input your text here');
E.element('#filters-current textarea[name=profile]').removeAttribute('disabled');
}
};
E.elemid('profile-search-type-expr').onchange = function(e) {
if (e.target.checked) {
E.element('#filters-current textarea[name=profile]').setAttribute('placeholder',
'(words "apple,banana" AND contains "i like apples") OR words "pineapple,strawberry"');
E.element('#filters-current textarea[name=profile]').removeAttribute('disabled');
}
};
E.elemid('profile-search-type-empty').onchange = function(e) {
if (e.target.checked) {
E.element('#filters-current textarea[name=profile]').setAttribute('placeholder', '<Profile content is empty>');
E.element('#filters-current textarea[name=profile]').setAttribute('disabled', 'disabled');
E.element("#filters-current textarea[name=profile]").value = '';
}
}
E.custom.btncollapse_render();
http.get('api/v1/config/filters/get?type=users', {}, function(js) {
js = js.sort((a,b) => a.preset_name.localeCompare(b.preset_name));
window.vars.user_filters = js;
E.template('filters-all', function(TPL) {
var html = '';
for (var i = 0; i < js.length; i++) {
var tpl = TPL;
tpl = tpl.replaceAll('{id}', js[i].id);
tpl = tpl.replaceAll('{name}', js[i].preset_name);
html += tpl;
}
return html;
});
if (hargs.filter_id !== undefined)
window.view.instance.do.filter_users.set_current_filter(hargs.filter_id);
});
});
},
},
load_content: function(content, click) {
click = click === undefined ? false : click;
const hargs = get_hash_arguments();
const _empty_content = function() {
E.element('#window-instance #container').innerHTML = '';
};
if (click) {
delete window.hash_argument_nofirechange;
del_hash_argument('filter_id', false);
}
switch (content) {
case 'home':
_empty_content();
window.location.hash = '#home';
return;
case 'settings':
_empty_content();
return window.view.instance.show_config();
default:
_empty_content();
set_hash_argument('content', content, false);
return window.view.instance
.load[content.replaceAll('-','_')]();
}
},
};
function title__instance() {}
function load__instance(args) {
const hargs = get_hash_arguments();
const _error400 = function(msg) {
msg = msg || 'Parameters are not correct';
toast.error(msg);
};
const _paint = function() {
const menu = [
{
id: 'home',
title: '',
icon: 'home',
},
{
id: 'filter-users',
title: 'Users filter',
icon: 'user',
},
{
id: 'filter-posts',
title: 'Posts filter',
icon: 'file-text',
},
{
id: 'new-accounts',
title: 'New accounts',
icon: 'user-plus',
},
{
id: 'settings',
title: hargs['instance'],
icon: 'gear',
},
];
E.template('tabs', function(TPL) {
var html = '';
for (var i = 0; i < menu.length; i++) {
var tpl = TPL;
tpl = tpl.replaceAll('{id}', menu[i]['id']);
tpl = tpl.replaceAll('{title}', menu[i]['title']);
tpl = tpl.replaceAll('{icon}', menu[i]['icon']);
html += tpl;
}
return html;
});
if (hargs['content'] !== undefined)
window.view.instance.load_content(hargs['content']);
};
const _main = function() {
if (hargs['software'] === undefined ||
!window.vars['instance_config']['supported_ap_software']
.includes(hargs['software']))
return _error400();
if (hargs['instance'] === undefined)
return _error400();
var found = false;
for (var i = 0; i < window.vars['instance_config']['hosts'][hargs['software']].length; i++)
{
const item = window.vars['instance_config']['hosts'][hargs['software']][i];
if (item['instance'] === hargs['instance']) {
window.vars['current_instance'] = item;
found = true;
break;
}
}
if (!found)
return _error400();
apcontrol_title(`Instance (${hargs['instance']})`);
const config = parse_ini_config(window.vars['current_instance']['config']);
const fields = window.consts['instance_config'][hargs['software']]['fields'];
for (var i = 0; i < fields.length; i++) {
if (!fields[i].startsWith('*'))
continue;
const f = fields[i].substr(1);
if (config[f] === undefined) {
window.view.instance.show_config();
return false;
}
}
return _paint();
};
if (window.vars['instance_config'] === undefined) {
http.get('api/v1/config/get',{},function(data) {
window.vars['instance_config'] = JSON.parse(data);
_main();
});
} else { _main() }
}
</script>