View Full Version : vBulletin 5 Request - Require (New Thread), (Edit Thread), (New Post), and (Move Post) Functions VB5.2.3
Necrophyte
08-22-2016, 01:29 AM
Require (New Thread), (Edit Thread), (New Post), and (Move Thread) Functions
As it says. I've have an external application from VB4 that used to do the above. However VB5 has changed so much. I haven't been able to figure using external code.
Example Function was:
function writepost($userid, $threadid, $postmsg, $title){
global $vbulletin;
if (!is_numeric($threadid)){
return;
}
chdir($_SERVER['DOCUMENT_ROOT']."/forum");
require_once './global.php';
require_once './includes/class_dm.php';
require_once './includes/class_dm_threadpost.php';
require_once './includes/functions_databuild.php';
require_once('./includes/class_wysiwygparser.php');
chdir($_SERVER['DOCUMENT_ROOT']."/opserv");
$html_parser = new vB_WysiwygHtmlParser($vbulletin);
$postmsg = html_entity_decode($html_parser->parse_wysiwyg_html_to_bbcode($postmsg, false), ENT_QUOTES, 'UTF-8');
$userid = (int)$row['userid'];
$postdm = new vB_DataManager_Post($vbulletin, ERRTYPE_STANDARD);
$threadinfo = fetch_threadinfo($threadid);
$foruminfo = fetch_foruminfo($threadinfo['forumid']);
$postdm->set_info('forum', $foruminfo);
$postdm->set_info('thread', $threadinfo);
$postdm->set('userid', $userid);
$postdm->set('title', $title);
$postdm->set('threadid', $threadid);
$postdm->set('pagetext', $postmsg);
$postdm->set('allowsmilie', 1);
$postdm->set('visible', 1);
$postdm->set('dateline', TIMENOW);
$postid = $postdm->save();
build_forum_counters($threadinfo['forumid']);
unset($postdm);
return $postid;
}
I need the same style functions for:
function writepost($userid, $threadid, $postmsg, $title)
Must return post id
function startpost($userid, $forum_id, $postmsg, $title)
Must return Thread id
function editpost($userid, $postid, $postmsg, $title)
Must return Post id
function movethread($threadid, $forumid)
Must return true false
Each one needs to update the forums properly as well ie: Build forum counters or the equivalent in VB5. Startpost was a function that started the initial thread. Not sure if VB5 requires the same. Writepost would write a new post in a current thread. Edit post is where it would edit an existing post, and movethread would move a thread from one forumid to another.
I've honestly Tried. I just can't figure out how VB5 does it, and I don't want to give up on VB5.
I've looked through createcontent.php and I still can't figure out how its done. Someone please help.
Replicant
08-22-2016, 03:24 AM
Starting a thread and posting to a thread is a simple post operation. Here's a sample JSON string that has the minimum requirements for a post or new thread. The CKEditor uses a multi-part binary postfor uploading pics and what not. A lot more code. Writing to a forum nodeid will return a nodeid for the newly created thread. Writing to a thread nodeid will return a nodeid for the new post in that thread. Writing to a Post nodeid will return the nodeid for the newly created comment. Your json string would by submitted via POST (required) to the /create-content/text url. You can use JS, Jquery, curl, or any other http protocol that is http compliant. I've used the Bash shell in Linux using the POST command.
{ "data":{"title":"Sample Title", "securitytoken":"Valid Security Token", "parentid"="Forum or Thread or Post nodeid"}}
Moving a thread can be accopmlished with a POST to /ajax/api/node/movePosts. Data required is
newtitle="Hello World", to_parent=Forum Nodeid , nodeids[] = 9305 (Array is Required), securitytoken=Valid token.
Editing an existing post will be trickier. The post request for editing pulls a ckeditor template. You can make POST nodeid="post-to-be-edited" to /api/node/getNodeContent (permissions required). That will give you a JSON string with all the info about that nodeid including the bbcode held in the rawtext field. You can import that code into your app for editing then save to create-content/Text/. You will need to get the params from the dev environment while saving a edited post. It'll be multipart binary so You'll have to play with it a bit. It's not too difficult.
Most if not all of the functions can also be done in php but I figure why bother? The VB5 api has all the checks, security, and verification in place already and puts everything where it;'s supposed to be in the database.
Good Luck.
Necrophyte
08-22-2016, 01:06 PM
Replicant,
First let me thank you for responding.
I get what your saying but here's the issue that I have.
Some of the people don't have the permissions required when these posts are made or edited. They are sent to their command and staff where only they have access to it. But it's an automated post of stuff have done for the day. Sometimes when they redo something. It will go back and edit the post and add to it automatically. Nothing that is in the post is typed by the user. I'm not using ckeditor in any way. Its all an internal script that when someone does a part of a job it writes a new thread once its been marked done.
If it was a user doing something with ckeditor I can totally get where your coming from and it would only make sense to do it that way. But its an automated post.
I've tried doing it via PHP. I've at least think I figured out the code to do it:
define('VB_ENTRY', 1);
$input = array(
'title' => (isset($_POST['title']) ? trim(strval($_POST['title'])) : ''),
'text' => (isset($_POST['text']) ? trim(strval($_POST['text'])) : ''),
'nodeid' => (isset($_POST['nodeid']) ? trim(intval($_POST['nodeid'])) : 0),
'parentid' => (isset($_POST['parentid']) ? trim(intval($_POST['parentid'])) : 0),
'channelid' => (isset($_POST['channelid']) ? trim(intval($_POST['channelid'])) : 0),
'ret' => (isset($_POST['ret']) ? trim(strval($_POST['ret'])) : ''),
'tags' => (isset($_POST['tags']) ? $_POST['tags'] : ''),
'reason' => (isset($_POST['reason']) ? trim(strval($_POST['reason'])) : ''), //used in editing a post
'iconid' => (isset($_POST['iconid']) ? intval($_POST['iconid']) : 0),
'prefixid' => (isset($_POST['prefixid']) ? trim(strval($_POST['prefixid'])) : ''),
'hvinput' => (isset($_POST['humanverify']) ? $_POST['humanverify'] : ''),
'subtype' => (isset($_POST['subtype']) ? trim(strval($_POST['subtype'])) : ''),
'nl2br' => (isset($_POST['nl2br']) ? (bool)$_POST['nl2br'] : false),
);
$api = Api_InterfaceAbstract::instance();
if (!empty($_POST['setfor']))
{
$input['setfor'] = $_POST['setfor'];
}
if (!empty($_POST['recaptcha_challenge_field']))
{
// reCaptcha fields
$input['hvinput']['recaptcha_challenge_field'] = $_POST['recaptcha_challenge_field'];
$input['hvinput']['recaptcha_response_field'] = $_POST['recaptcha_response_field'];
}
// get user info for the currently logged in user
$user = $api->callApi('user', 'fetchUserinfo', array());
$time = vB5_Request::get('timeNow');
$tagRet = false;
$textData = array(
'title' => $input['title'],
'parentid' => $input['parentid'],
'prefixid' => $input['prefixid'],
'iconid' => $input['iconid'],
);
if ($input['nodeid'])
{
$result = array();
if ($user['userid'] < 1)
{
$result['error'] = 'logged_out_while_editing_post';
$this->sendAsJson($result);
exit;
}
// when *editing* comments, it uses create-content/text (this function)
// when *creating* comments, it uses ajax/post-comment (actionPostComment)
if ($input['subtype'] == 'comment')
{
// NOTE: Keep this in sync with
// vB5_Frontend_Controller_Ajax:: actionPostComment
//
// htmlspecialchars and nl2br puts the text into the same state
// it is when the text api receives input from ckeditor
// specifically, newlines are passed as <br /> and any HTML tags
// that are typed literally into the editor are passed as HTML-escaped
// because non-escaped HTML that is sent is assumed to be formatting
// generated by ckeditor and will be parsed & converted to bbcode.
$textData['rawtext'] = nl2br(htmlspecialchars($input['text'], ENT_NOQUOTES));
}
else
{
$textData['rawtext'] = $input['text'];
}
$textData['reason'] = $input['reason'];
$textData += $this->getArticleInput();
$options = array();
// We need to convert WYSIWYG html here and run the img check
if (isset($textData['rawtext']))
{
$tmpText = $api->callApi('bbcode', 'convertWysiwygTextToBbcode', array($textData['rawtext'], $options));
// Check Images
if (($phrase = vB5_Frontend_Controller_Bbcode::verifyImgCheck($tm pText)) !== true)
{
$results['error'] = $phrase;
$this->sendAsJson($results);
return;
}
}
if ($input['nl2br'])
{
// not using ckeditor (on edit, 'nl2br' goes in the data array)
$textData['nl2br'] = true;
}
// add attachment info so update() can do permission checking & add/remove attachments to this node.
$this->addAttachments($textData);
$updateRet = $api->callApi('content_text', 'update', array($input['nodeid'], $textData, $options));
$this->handleErrorsForAjax($result, $updateRet);
// If the update failed, just return and don't edit tags, attachments etc.
if (!empty($updateRet['errors']))
{
return $this->sendAsJson($result);
}
//update tags
$tags = !empty($input['tags']) ? explode(',', $input['tags']) : array();
$tagRet = $api->callApi('tags', 'updateUserTags', array($input['nodeid'], $tags));
$this->handleErrorsForAjax($result, $tagRet);
$this->sendAsJson($result);
}
else
{
//not sure why rawtext is different here from the above
$textData['rawtext'] = $input['text'];
$textData['userid'] = $user['userid'];
$textData['authorname'] = $user['username'];
$textData['created'] = $time;
$textData['hvinput'] = $input['hvinput'];
$publish = array(
'facebook' => !empty($_POST['fbpublish'])
);
if (!empty($_POST['setfor']))
{
$textData['setfor'] = intval($_POST['setfor']);
}
if(!$this->createNewNode('content_text', $textData, $publish, $input))
{
return;
}
}
However this code keeps asking for more and more includes, I stopped on the 7th one cause it started giving multiple errors that were not related to the code shown. I've got until Sept to figure this out and at the current rate I'll not figure this out in time. I'll have to abandon vBulletin and I'd really rather not do that.
Replicant
08-22-2016, 01:42 PM
So this is a guest user post? What is the text input user interface? What are you getting the errors thrown on...editing or posting? Are you using the mapi interface or a web browser interface?
Necrophyte
08-22-2016, 02:22 PM
No sir. It gets the user info from $vbulletin->userinfo.
The text input is a variable generated. Sample is:
while ($billetRow = $billetResult->fetch_assoc()){
$post_text.= "".($billetRow['opid'] == 30 ? $row['tag']. " - ". $row['officename'] : $billetRow['tag']. " - ". $billetRow['opname'])." " .$billetRow['billetname']. " (."']".$billetRow['title']."): ".(get_billet_username($billetRow['billetid']) == "N/A" ? "Vacant" : "."/forum/member.php?".userExists(get_billet_username($billetRow['billetid']))."-".get_billet_username($billetRow['billetid'])."]".get_billet_username($billetRow['billetid'])." (http://".$_SERVER['HTTP_HOST')")."";
}
There is a lot more to it than that, however $post_text is auto generated, and that is what is the text. The interface would be a web browser with php coded interface. They just log onto a site (External page, loaded with .global.php) and click a checkbox. Click save. The form submits as post. This goes through all the checked information creating a $post_text then calls the write a new thread function. That writes the post, and he/she is brought back to the screen with all the checkboxes updated, (Clicked or un-clicked). At which point they can then add or remove checked boxes. Submit again. And this will run through the post. See the thread exists, and will replace the data in the above mentioned post.
At a specific time, a php script is run at night and it will move the thread to another forum to be audited later.
Dragonsys
08-22-2016, 02:51 PM
Can you go back to vb4?
Replicant
08-22-2016, 02:52 PM
then calls the write a new thread function.
Instead of calling the function directly, you can use cURL in the php script to submit to create-content. Since it is a web browser interface, JS can be used to retrieve the data and fill the forms for editing and saving. If this is a secure interface keeping anyone from logging in and posting from the net or network, you can add an ip addr check at the beginning of the index() function in the create-content frontend controller so that it can only be posted from that machine (or whitelisted IPs in the list).
Necrophyte
08-22-2016, 03:27 PM
At Dragonsys. Currently there is no undo for the database. I've seen a couple folks that have managed to convert back but at this point I feel it would be easier to get this working.
Oh oh oh.. As I write this I've gotten a working write a new post in an existing thread in php. So its not seeming so bleak. But I need to figure out how to write a new thread. Now that I have figured this out, I'm pretty sure I can get the rest in time. It's not pretty. But it works.
My issue btw was the:
vB5_Autoloader::register(dirname(__FILE__));
dirname(__FILE__) grabs your current working folder so I changed this to be the forums and solved the rest of my issues at least for creating a post.
I've posted this code so that if someone needed something like I did they can use it. Its not cleaned up, as I'm not sure what needs to stay or go yet. But it works, and should get you where you need to go.
<?PHP
// Attempt for creating thread code
define('VB_ENTRY', 1);
chdir($_SERVER['DOCUMENT_ROOT']."/forum/core");
require_once('./global.php');
require_once('../includes/vb5/autoloader.php');
vB5_Autoloader::register($_SERVER['DOCUMENT_ROOT']."/forum");
$app = vB5_Frontend_Application::init('config.php');
$options = [];
$input = array(
'title' => 'Posting through the API',
'rawtext' => 'Edited more Change text3',
'nodeid' => 1099448,
'parentid' => 85,
'channelid' => 85,
'ret' => '',
'tags' => '',
'reason' => '',
'iconid' => '',
'prefixid' => '',
'hvinput' => '',
'subtype' => '',
'userid' => '1',
'username' => 'User',
'nl2br' => (isset($_POST['nl2br']) ? (bool)$_POST['nl2br'] : false),
);
$api = Api_InterfaceAbstract::instance();
if (!empty($_POST['setfor']))
{
$input['setfor'] = $_POST['setfor'];
}
// get user info for the currently logged in user
$user = $api->callApi('user', 'fetchUserinfo', array());
$time = vB5_Request::get('timeNow');
$tagRet = false;
$textData = array(
'title' => $input['title'],
'parentid' => $input['parentid'],
'prefixid' => $input['prefixid'],
'iconid' => $input['iconid'],
);
if ($input['nodeid']){ //If we're here. We are to edit a post.
$result = array();
if ($user['userid'] < 1){
$result['error'] = 'logged_out_while_editing_post';
echo $result['error'];
exit;
}
$textData['rawtext'] = $input['rawtext'];
$textData['reason'] = $input['reason'];
// $textData += $this->getArticleInput();
$options = array();
// We need to convert WYSIWYG html here and run the img check
if (isset($textData['rawtext'])){
$tmpText = $api->callApi('bbcode', 'convertWysiwygTextToBbcode', array($textData['rawtext'], $options));
// Check Images
if (!$phrase = vB5_Frontend_Controller_Bbcode::verifyImgCheck($tm pText)){
$result['error'] = $phrase;
echo "Result:".$result['error'];
exit;
}
}
if ($input['nl2br'])
{
// not using ckeditor (on edit, 'nl2br' goes in the data array)
$textData['nl2br'] = true;
}
$nodeId = $api->callApi('content_text', 'update', [$input['nodeid'], $textData, $options]);
//update tags
$tags = !empty($input['tags']) ? explode(',', $input['tags']) : array();
$tagRet = $api->callApi('tags', 'updateUserTags', array($input['nodeid'], $tags));
}
else //Here we start a new post/thread
{
$nodeId = $api->callApi('content_text', 'add', [$input, $options]);
}
if ($nodeId == '1'){
echo "updated";
}
if(!is_int($nodeId))
{
echo "Array";
print_r($nodeId);
exit;
}
print 'Node '. $nodeId . ' created successfully';
?>
Replicant
08-22-2016, 03:29 PM
If you wrote to an existing thread, change the thread nodeid you wrote to to the forum nodeid and it will create a new thread.
Necrophyte
08-22-2016, 03:34 PM
Replicant. That worked like a charm! This also allows to edit. Its all I need in one function. Pretty amazing.
Thank you for all your help Replicant. In this and the other things you've assisted me with.
You are a gentleman and a scholar, and some day, people will sing songs of your glory!
You most certainly are appreciated. By me at least.
Again. Thank you!
--------------- Added 1471962005 at 1471962005 ---------------
I've come across the dilemma of no permissions when trying to use this which I was afraid of. Is there a trick to bypass this? Or is it way more in depth. I fear for me, that I'm back at square one.
noypiscripter
08-24-2016, 07:18 PM
I have done something similar to this. I created an API wrapper in the frontend controller. You don't have to include any file at all.
Create a php file named apiwrapper.php in /includes/vb5/frontend/controller directory. The class name suffix has to match the filename.
<?php
class vB5_Frontend_Controller_ApiWrapper extends vB5_Frontend_Controller
{
public function __construct() {
parent::__construct();
}
public function actionCreatePost() {
// validate ip address to restrict unauthorized calls
// validate input data in $_POST
// set user session to a user that has create post permission:
// $this->setUserSession(1);
// call content api to create the node passing all the required parameters:
// $nodeid = Api_InterfaceAbstract::instance()->callApi('content_text', 'add', array($data, array())); // $data is an array containing title, parentid, rawtext, userid, etc.
// return the nodeid generated as a JSON:
// $result['nodeid'] = $nodeid;
// $this->sendAsJson($result);
}
protected function setUserSession($postUserId) {
$session = vB::getCurrentSession();
$userid = $session->get('userid');
if ($userid != $postUserId) {
$newsession = new vB_Session_Cli(vB::getDbAssertor(), vB::getDatastore(), vB::getConfig(), $postUserId);
vB::setCurrentSession($newsession);
}
}
}
To call actionCreatePost() method, use CURL, jQuery (if forum is on same domain as the originating call) or any tool/library that supports HTTP transfer. The URL endpoint for the call is http://yourdomain.com/apiwrapper/createPost then you have to pass the parameters as POST data.
Necrophyte
08-26-2016, 01:41 PM
Glenn, Thank you for the assist. This is great if you want to post as someone else. (I will definitely keep this, I'm sure I can use it). What I was trying to do is. Right after the member has been approved, and the save has completed, but before the welcome email has been sent. I needed it to send a post to a forum that is accessible to usergroup 2. Problem is. They are not usergroup 2 yet at that point, even though its saved. However. I was able to take a chunk of your code
$newsession = new vB_Session_Cli(vB::getDbAssertor(), vB::getDatastore(), vB::getConfig(), $postUserId);
vB::setCurrentSession($newsession);
put that before the api call. This updated their saved status and allowed them to make the post.
This way I have the postid, and I can use it in the welcome email to tell the user to watch the post for questions on their recruitment.
No code modified. I wouldn't have been able to do it without your section of code, or the idea to change user sessions. So thank you very much. You and Replicant are a great value to this community. I don't care what they say about you ;)
Replicant
08-26-2016, 03:36 PM
Glenn has been my mentor from the beginning. His tips on CSS are what got me started. I'm not a coder, just more of a hacker and I have learned a ton of how to do things in vb5 from Glenn. His examples allowed me to understand what's going on in the back end more so than would have been possible on my own. Some of his posts, like the previous one are very illuminating.
noypiscripter
08-26-2016, 09:18 PM
Glad to help @Necrophyte. :)
@Replicant, I'm impressed that you learned to code when you are not a coder. :)
Replicant
08-27-2016, 06:42 PM
Thanks Glenn. I'm still learning and have a long way to go. If I had to depend on coding skills to eat, I'd be starving :) These little mod projects help a lot with understanding the quirks of PHP. I've done a ton of bash scripting over the last 20 years, but PHP is a whole different animal. At least with a background in bash, I'm able to read the code and figure out what it's doing most of the time. It's the syntax and the array handling that gets me confused sometimes. It's coming right along though.
Necrophyte
08-28-2016, 03:52 PM
I have to agree. You both have taught me much. My eyes started to glaze over on some of the stuff you guys were talking about. I do Database management, with some php scripts here and there to modify data and manipulate the database here and there. But never to the extend vBulletin is.
I'm sure I'll have many more questions.
vBulletin® v3.8.12 by vBS, Copyright ©2000-2025, vBulletin Solutions Inc.