$ git clone https://thingshare.ion.nu/thingshare.git
commit 6f1d70b603f5c7d3a4ddef1dfb7c74a225d7f990
Author: Alicia <...>
Date: Thu Dec 16 19:02:31 2021 +0100
Long overdue tag opt-in feature.
diff --git a/admin_tags.php b/admin_tags.php
index 23d40b0..8624dcb 100644
--- a/admin_tags.php
+++ b/admin_tags.php
@@ -2,7 +2,7 @@
/*
This file is part of Thingshare, a federated system for sharing data for home manufacturing (e.g. 3D models to 3D print)
https://thingshare.ion.nu/
- Copyright (C) 2020 Alicia <...>
+ Copyright (C) 2020-2021 Alicia <...>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
@@ -44,7 +44,7 @@ if(checknonce()) // Save changes
}
}
mysqli_query($db, 'delete from tags where name="'.$tag.'"');
- mysqli_query($db, 'insert into tags(name, blacklist) values("'.$tag.'", '.$blacklist.')');
+ mysqli_query($db, 'insert into tags(name, blacklist, optin) values("'.$tag.'", '.$blacklist.', "")');
}
if(isset($_POST['deletetag']))
{
@@ -52,19 +52,46 @@ if(checknonce()) // Save changes
mysqli_query($db, 'delete from tagmaps where tag="'.$tag.'"');
mysqli_query($db, 'delete from tags where id="'.$tag.'"');
}
+ if(isset($_POST['tag_optin']))
+ {
+ $id=(int)$path[3];
+ $optin=mysqli_real_escape_string($db, $_POST['tag_optin']);
+ mysqli_query($db, 'update tags set optin="'.$optin.'" where id='.$id);
+ header('Location: '.BASEURL.'/admin/tags');
+ }
}
if($error!=''){$error='<span class="error">'.$error.'</span>';}
// Load current
-$tags='';
-$res=mysqli_query($db, 'select name, blacklist, id from tags order by name asc');
-while($row=mysqli_fetch_assoc($res))
+if(!isset($path[3]))
{
- $name=htmlentities($row['name']);
- if($row['blacklist']){$name='<span class="blacklist">'.$name.'</span>';}
- $tags.=$name.'<button name="deletetag" value="'.$row['id'].'">X</button><br />';
+ $tags='';
+ $res=mysqli_query($db, 'select name, blacklist, id from tags order by name asc');
+ while($row=mysqli_fetch_assoc($res))
+ {
+ $name=htmlentities($row['name']);
+ if($row['blacklist']){$name='<span class="blacklist">'.$name.'</span>';}
+ $tags.='<a href="'.BASEURL.'/admin/tags/'.$row['id'].'">'.$name.'</a> <button name="deletetag" value="'.$row['id'].'">X</button><br />';
+ }
+ $usertagscheck=(getoption('usertags', true)?' checked':'');
+}else{ // Individual tag
+ $id=(int)$path[3];
+ $res=mysqli_query($db, 'select name, blacklist, optin from tags where id='.$id);
+ $res=mysqli_fetch_assoc($res);
+ $name=$res['name'];
+ if($res['blacklist'])
+ {
+ $optin='';
+ $placeholder='"'._('Blacklisted').'" disabled';
+ }else{
+ $optin=htmlentities($res['optin']);
+ $placeholder='"'._('No opt-in required').'"';
+ }
+ $res=mysqli_query($db, 'select count(*) from tagmaps where tag='.$id);
+ $numtags=mysqli_fetch_row($res)[0];
}
-$usertagscheck=(getoption('usertags', true)?' checked':'');
+if(!isset($path[3]))
+{
?>
<?=$error?>
<form method="post"><?=nonce()?>
@@ -77,3 +104,13 @@ $usertagscheck=(getoption('usertags', true)?' checked':'');
<?=$tags?>
<input type="text" name="newtag" /><button name="addtag"><?=_('Add tag')?></button><button name="blacklisttag" title="<?=_('Don\'t allow this tag to be added')?>"><?=_('Add tag to blacklist')?></button><br />
</form>
+<?php }else{ /* Individual tag */ ?>
+<h2>Tag '<?=$name?>'</h2>
+<p><?=sprintf(_('%s things tagged on this node.'), $numtags)?></p>
+<form method="post"><?=nonce()?>
+ <?=_('Opt-in text:')?><br />
+ <textarea name="tag_optin" rows="12" style="width:100%;" placeholder=<?=$placeholder?>><?=$optin?></textarea><br />
+ <input type="submit" value="<?=_('Save')?>" />
+</form>
+<a href="<?=BASEURL?>/admin/tags"><button><?=_('Back')?></button></a>
+<?php } ?>
diff --git a/db.php b/db.php
index ffdd2b4..27c3b48 100644
--- a/db.php
+++ b/db.php
@@ -120,8 +120,9 @@ function db_create_tables()
latest boolean);');
mysqli_query($db, 'create table userblocks(user integer, blocked text);');
mysqli_query($db, 'create table loginfails(ip varchar(256), timestamp datetime);');
- mysqli_query($db, 'create table tags(id integer primary key auto_increment, name text, blacklist boolean);');
+ mysqli_query($db, 'create table tags(id integer primary key auto_increment, name text, blacklist boolean, optin text);');
mysqli_query($db, 'create table tagmaps(tag integer, thing integer);');
+ mysqli_query($db, 'create table tag_optins(tag integer, user integer);');
mysqli_query($db, 'create table comments(id integer primary key auto_increment,
thing integer,
sender text,
diff --git a/docs/RPCs b/docs/RPCs
index fa56ebc..86c5118 100644
--- a/docs/RPCs
+++ b/docs/RPCs
@@ -48,7 +48,10 @@ Return format:
"by": {
"displayname": <User's display name>,
"name": <Username, without node>
- }
+ },
+ "tags": [
+ <Tag names>
+ ]
},
<More entries in the same format as the first. One for every result>
]
diff --git a/rpc_search.php b/rpc_search.php
index 2ce2b3e..a58128e 100644
--- a/rpc_search.php
+++ b/rpc_search.php
@@ -2,7 +2,7 @@
/*
This file is part of Thingshare, a federated system for sharing data for home manufacturing (e.g. 3D models to 3D print)
https://thingshare.ion.nu/
- Copyright (C) 2020 Alicia <...>
+ Copyright (C) 2020-2021 Alicia <...>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
@@ -87,16 +87,24 @@ while($row=mysqli_fetch_assoc($res))
$thing=Array('id'=>$row['thingid'],
'name'=>$row['name'],
'description'=>$row['description'],
- 'date'=>$row['posted']);
+ 'date'=>$row['posted'],
+ 'tags'=>Array());
$user=$row['user'];
+ $revid=(int)$row['id'];
// Grab preview from the chosen file, or the first file if none is chosen for preview
- $res2=mysqli_query($db, 'select name, hash from files where thing='.(int)$row['id'].' order by preview desc limit 1');
+ $res2=mysqli_query($db, 'select name, hash from files where thing='.$revid.' order by preview desc limit 1');
$row=mysqli_fetch_assoc($res2);
$thing['preview']=getpreview($row['name'], $row['hash']);
// Designer
$res2=mysqli_query($db, 'select displayname, name from users where id='.$user);
$row=mysqli_fetch_assoc($res2);
$thing['by']=$row;
+ // Tags
+ $res2=mysqli_query($db, 'select tags.name from tags, tagmaps where tags.id=tagmaps.tag and tagmaps.thing='.$revid);
+ while($row=mysqli_fetch_row($res2))
+ {
+ $thing['tags'][]=$row[0];
+ }
$obj[]=$thing;
}
print(json_encode($obj));
diff --git a/search.php b/search.php
index 1561f21..eefadd2 100644
--- a/search.php
+++ b/search.php
@@ -28,6 +28,18 @@ while($row=mysqli_fetch_row($res)){$peers[]=$row[0];}
$filtertags='';
$res=mysqli_query($db, 'select tag from filtertags');
while($row=mysqli_fetch_row($res)){$filtertags.=' tag:-'.$row[0];}
+// Get list of tags to hide content for (e.g. 'nsfw')
+$hiddentags=Array();
+$res=mysqli_query($db, 'select name, id from tags where optin!=""');
+while($row=mysqli_fetch_assoc($res))
+{
+ if(isset($_SESSION['id'])) // Check if user opted in
+ {
+ $res2=mysqli_query($db, 'select tag from tag_optins where tag='.(int)$row['id'].' and user='.(int)$_SESSION['id']);
+ if(mysqli_fetch_row($res2)){continue;}
+ }
+ $hiddentags[]=$row['name'];
+}
// Pagination
$perpage=(isset($_GET['perpage'])?(int)$_GET['perpage']:20);
$page=(int)(isset($_GET['page'])?$_GET['page']:0);
diff --git a/thing.php b/thing.php
index 3bdff6f..5ab7052 100644
--- a/thing.php
+++ b/thing.php
@@ -36,22 +36,34 @@ if(isset($_SESSION['id']))
$blocked=mysqli_fetch_row($res);
$info='';
$error='';
- if(isset($_POST['msg']) && checknonce())
+ if(checknonce())
{
- if($blocked){$error=_('Cannot send messages to blocked users');}else{
- // Send it to thing's node
- $msg=Array('from'=>$_SESSION['name'],
- 'message'=>$_POST['msg'],
- 'replyto'=>$_POST['replyto']);
- $data=rpc_post($thing[1], 'comments/'.$thing[0], $msg);
- if(isset($data['error']))
+ if(isset($_POST['msg']))
+ {
+ if($blocked){$error=_('Cannot send messages to blocked users');}else{
+ // Send it to thing's node
+ $msg=Array('from'=>$_SESSION['name'],
+ 'message'=>$_POST['msg'],
+ 'replyto'=>$_POST['replyto']);
+ $data=rpc_post($thing[1], 'comments/'.$thing[0], $msg);
+ if(isset($data['error']))
+ {
+ $error=$data['error'];
+ if(isset($_POST['asyncrequest'])){exit($error);}
+ }else{
+ rpc_cache($thing[1], 'comments/'.$thing[0], false); // Invalidate cache to show new comments
+ if(isset($_POST['asyncrequest'])){exit('ok:'.$data['id']);}
+ $info=_('Comment posted');
+ }
+ }
+ }
+ if(isset($_POST['tag_optin']))
+ {
+ $tag_name=mysqli_real_escape_string($db, $_POST['tag_optin']);
+ $res=mysqli_query($db, 'select id from tags where optin!="" and name="'.$tag_name.'"');
+ if($res=mysqli_fetch_row($res))
{
- $error=$data['error'];
- if(isset($_POST['asyncrequest'])){exit($error);}
- }else{
- rpc_cache($thing[1], 'comments/'.$thing[0], false); // Invalidate cache to show new comments
- if(isset($_POST['asyncrequest'])){exit('ok:'.$data['id']);}
- $info=_('Comment posted');
+ mysqli_query($db, 'insert into tag_optins(tag, user) values('.(int)$res[0].', '.(int)$_SESSION['id'].')');
}
}
}
@@ -98,6 +110,34 @@ foreach($thingobj['files'] as $file)
$tags='';
foreach($thingobj['tags'] as $tag)
{
+ if(!isset($_GET['show_'.strtolower($tag).'_content']) || $_GET['show_'.strtolower($tag).'_content']!='true')
+ {
+ // Check if tag requires optin
+ $tagname=mysqli_real_escape_string($db, $tag);
+ $res=mysqli_query($db, 'select id, optin from tags where name="'.$tagname.'"');
+ $optin=mysqli_fetch_assoc($res);
+ if($optin['optin']!='' && isset($_SESSION['id'])) // Check if user is already opted in
+ {
+ $res=mysqli_query($db, 'select tag from tag_optins where tag='.(int)$optin['id'].' and user='.(int)$_SESSION['id']);
+ if(mysqli_fetch_row($res)){$optin['optin']='';} // Just act like the optin doesn't exist
+ }
+ if($optin['optin']!='')
+ {
+ $showurl=$_SERVER['REQUEST_URI'];
+ $showurl.=(substr_count($showurl, '?')?'&':'?').'show_'.strtolower($tag).'_content=true';
+ print('<center>'.$optin['optin'].'<br />');
+ print('<a href="'.$showurl.'"><button>'.sprintf(_('Show %s content'), htmlentities($tag)).'</button></a>');
+ if(isset($_SESSION['id']))
+ {
+ print('<form method="post" style="display:inline;">'.nonce());
+ print('<button name="tag_optin" value="'.htmlentities($tag).'">'.sprintf(_('Always show %s content'), htmlentities($tag)).'</button>');
+ print('</form>');
+ }
+ print('</center>');
+ include_once('footer.php');
+ exit();
+ }
+ }
$tag=htmlentities($tag);
$tags.=' <a href="'.BASEURL.'/tag/'.$tag.'">'.$tag.'</a>';
}