Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions controller/idea_controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,23 @@ public function ticket()
return false;
}

/**
* Implemented action (sets an idea's implemented phpBB version)
*
* @return bool True if set, false if not
* @access public
*/
public function implemented()
{
if ($this->is_mod() && check_link_hash($this->get_hash(), "implemented_{$this->data['idea_id']}"))
{
$version = $this->request->variable('implemented', '');
return $this->ideas->set_implemented($this->data['idea_id'], $version);
}

return false;
}

/**
* Title action (sets an idea's title)
*
Expand Down
2 changes: 2 additions & 0 deletions event/listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ public function show_idea($event)
'IDEA_DUPLICATE' => $idea['duplicate_id'],
'IDEA_RFC' => $idea['rfc_link'],
'IDEA_TICKET' => $idea['ticket_id'],
'IDEA_IMPLEMENTED' => $idea['implemented_version'],

'U_IDEA_DUPLICATE' => $this->link_helper->get_idea_link((int) $idea['duplicate_id']),

Expand All @@ -229,6 +230,7 @@ public function show_idea($event)
'U_CHANGE_STATUS' => $this->link_helper->get_idea_link($idea['idea_id'], 'status', true),
'U_EDIT_DUPLICATE' => $this->link_helper->get_idea_link($idea['idea_id'], 'duplicate', true),
'U_EDIT_RFC' => $this->link_helper->get_idea_link($idea['idea_id'], 'rfc', true),
'U_EDIT_IMPLEMENTED'=> $this->link_helper->get_idea_link($idea['idea_id'], 'implemented', true),
'U_EDIT_TICKET' => $this->link_helper->get_idea_link($idea['idea_id'], 'ticket', true),
'U_REMOVE_VOTE' => $this->link_helper->get_idea_link($idea['idea_id'], 'removevote', true),
'U_IDEA_VOTE' => $this->link_helper->get_idea_link($idea['idea_id'], 'vote', true),
Expand Down
25 changes: 25 additions & 0 deletions factory/ideas.php
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,31 @@ public function set_ticket($idea_id, $ticket)
return true;
}

/**
* Sets the implemented version of an idea.
*
* @param int $idea_id ID of the idea to be updated.
* @param string $version Version of phpBB the idea was implemented in.
*
* @return bool True if set, false if invalid.
*/
public function set_implemented($idea_id, $version)
{
$match = '/^\d\.\d\.\d+(\-\w+)?$/';
if ($version && !preg_match($match, $version))
{
return false;
}

$sql_ary = array(
'implemented_version' => $version, // string is escaped by build_array()
);

$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);

return true;
}

/**
* Sets the title of an idea.
*
Expand Down
2 changes: 2 additions & 0 deletions language/en/common.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
'IDEAS_TITLE' => 'phpBB Ideas',
'IDEAS_NOT_AVAILABLE' => 'Ideas is not available at this time.',
'IMPLEMENTED' => 'Implemented',
'IMPLEMENTED_ERROR' => 'Must be a valid phpBB version number.',
'IMPLEMENTED_IDEAS' => 'Recently Implemented Ideas',
'IMPLEMENTED_VERSION' => 'phpBB version',
'IN_PROGRESS' => 'In Progress',
'INVALID' => 'Invalid',
'INVALID_VOTE' => 'Invalid vote; the number you entered was invalid.',
Expand Down
51 changes: 51 additions & 0 deletions migrations/m8_implemented_version.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
/**
*
* Ideas extension for the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/

namespace phpbb\ideas\migrations;

class m8_implemented_version extends \phpbb\db\migration\migration
{
public function effectively_installed()
{
return $this->db_tools->sql_column_exists($this->table_prefix . 'ideas_ideas', 'implemented_version');
}

static public function depends_on()
{
return array(
'\phpbb\ideas\migrations\m1_initial_schema',
'\phpbb\ideas\migrations\m4_update_statuses',
'\phpbb\ideas\migrations\m6_migrate_old_tables',
'\phpbb\ideas\migrations\m7_drop_old_tables',
);
}

public function update_schema()
{
return array(
'add_columns' => array(
$this->table_prefix . 'ideas_ideas' => array(
'implemented_version' => array('VCHAR', ''),
),
),
);
}

public function revert_schema()
{
return array(
'drop_columns' => array(
$this->table_prefix . 'ideas_ideas' => array(
'implemented_version',
),
),
);
}
}
14 changes: 12 additions & 2 deletions styles/prosilver/template/idea_body.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,25 @@
</dd>
{% endif %}
{% if IDEA_DUPLICATE or S_IS_MOD %}
<dt class="duplicatetoggle idealabel"{% if IDEA_STATUS_ID != 4 %} style="display:none"{% endif %}>{{ lang('DUPLICATE') ~ lang('COLON') }}</dt>
<dd class="duplicatetoggle" {% if IDEA_STATUS_ID != 4 %}style="display:none"{% endif %}>
<dt class="duplicatetoggle idealabel"{% if IDEA_STATUS_ID != STATUS_ARY.DUPLICATE %} style="display:none"{% endif %}>{{ lang('DUPLICATE') ~ lang('COLON') }}</dt>
<dd class="duplicatetoggle" {% if IDEA_STATUS_ID != STATUS_ARY.DUPLICATE %}style="display:none"{% endif %}>
<a id="duplicatelink" class="ideamodbtn" data-link="{{ U_IDEA_DUPLICATE }}" data-l-msg="{{ lang('IDEA_NUM') }}" {% if IDEA_DUPLICATE %}href="{{ U_IDEA_DUPLICATE }}">{{ lang('IDEA_NUM') }}{{ IDEA_DUPLICATE }}{% else %}style="display:none">{% endif %}</a>
{% if S_IS_MOD %}
<a href="{{ U_EDIT_DUPLICATE }}" id="duplicateedit" data-l-add="{{ lang('ADD') }}" data-l-edit="{{ lang('EDIT') }}">{% if IDEA_DUPLICATE %}<i class="fa fa-fw fa-pencil"></i>{{ lang('EDIT') }}{% else %}<i class="fa fa-fw fa-plus-circle"></i>{{ lang('ADD') }}{% endif %}</a>
<input type="text" id="duplicateeditinput" class="ideainput"{% if IDEA_DUPLICATE %} value="{{ IDEA_DUPLICATE }}"{% endif %} placeholder="###" data-l-err="{{ lang('ERROR') }}" data-l-msg="{{ lang('TICKET_ERROR_DUP') }}" />
{% endif %}
</dd>
{% endif %}
{% if IDEA_IMPLEMENTED or S_IS_MOD %}
<dt class="implementedtoggle idealabel"{% if IDEA_STATUS_ID != STATUS_ARY.IMPLEMENTED %} style="display:none"{% endif %}>{{ lang('IMPLEMENTED_VERSION') ~ lang('COLON') }}</dt>
<dd class="implementedtoggle" {% if IDEA_STATUS_ID != STATUS_ARY.IMPLEMENTED %}style="display:none"{% endif %}>
<span id="implementedversion"{% if not IDEA_IMPLEMENTED %} style="display:none;"{% endif %}>{{ IDEA_IMPLEMENTED }}</span>
{% if S_IS_MOD %}
<a href="{{ U_EDIT_IMPLEMENTED }}" id="implementededit" data-l-add="{{ lang('ADD') }}" data-l-edit="{{ lang('EDIT') }}">{% if IDEA_IMPLEMENTED %}<i class="fa fa-fw fa-pencil"></i>{{ lang('EDIT') }}{% else %}<i class="fa fa-fw fa-plus-circle"></i>{{ lang('ADD') }}{% endif %}</a>
<input type="text" id="implementededitinput" class="ideainput"{% if IDEA_IMPLEMENTED %} value="{{ IDEA_IMPLEMENTED }}"{% endif %} placeholder="3.x.x" data-l-err="{{ lang('ERROR') }}" data-l-msg="{{ lang('IMPLEMENTED_ERROR') }}" />
{% endif %}
</dd>
{% endif %}
</dl>
</div>
</div>
92 changes: 72 additions & 20 deletions styles/prosilver/template/ideas.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
rfcEdit: $('#rfcedit'),
rfcEditInput: $('#rfceditinput'),
rfcLink: $('#rfclink'),
implementedEdit: $('#implementededit'),
implementedEditInput: $('#implementededitinput'),
implementedVersion: $('#implementedversion'),
implementedToggle: $('.implementedtoggle'),
removeVote: $('.removevote'),
status: $('#status'),
successVoted: $('.successvoted'),
Expand Down Expand Up @@ -126,11 +130,8 @@
.removeClass()
.addClass('status-badge status-' + $this.find(':selected').val());

if (idea_is_duplicate()) {
$obj.duplicateToggle.show();
} else {
$obj.duplicateToggle.hide();
}
$obj.duplicateToggle.toggle(idea_is_duplicate());
$obj.implementedToggle.toggle(idea_is_implemented());
}
});
});
Expand Down Expand Up @@ -168,11 +169,7 @@

$this.hide();

$obj.rfcEdit.text(function() {
return value ? $(this).attr('data-l-edit') : $(this).attr('data-l-add');
}).prepend($('<i class="fa fa-fw"></i>').addClass(function() {
return value ? 'fa-pencil' : 'fa-plus-circle';
})).show();
$obj.rfcEdit.toggleAddEdit(value);
}
});
} else if (e.keyCode === keymap.ESC) {
Expand Down Expand Up @@ -226,11 +223,7 @@

$this.hide();

$obj.ticketEdit.text(function() {
return value ? $(this).attr('data-l-edit') : $(this).attr('data-l-add');
}).prepend($('<i class="fa fa-fw"></i>').addClass(function() {
return value ? 'fa-pencil' : 'fa-plus-circle';
})).show();
$obj.ticketEdit.toggleAddEdit(value);
}

});
Expand Down Expand Up @@ -287,11 +280,7 @@

$this.hide();

$obj.duplicateEdit.text(function() {
return value ? $(this).attr('data-l-edit') : $(this).attr('data-l-add');
}).prepend($('<i class="fa fa-fw"></i>').addClass(function() {
return value ? 'fa-pencil' : 'fa-plus-circle';
})).show();
$obj.duplicateEdit.toggleAddEdit(value);
}
});
} else if (e.keyCode === keymap.ESC) {
Expand All @@ -308,6 +297,61 @@
}
});

$obj.implementedEdit.on('click', function(e) {
e.preventDefault();

$obj.implementedEdit.add($obj.implementedVersion).hide();
$obj.implementedEditInput.show().focus();
});

$obj.implementedEditInput.on('keydown', function(e) {
if (e.keyCode === keymap.ENTER) {
e.preventDefault();
e.stopPropagation();

var $this = $(this),
find = /^\d\.\d\.\d+(\-\w+)?$/,
url = $obj.implementedEdit.attr('href'),
value = $this.val();

if (value && !find.test(value)) {
phpbb.alert($this.attr('data-l-err'), $this.attr('data-l-msg'));
return;
}

$.get(url, {implemented: value}, function(res) {
if (res) {
$obj.implementedVersion.text(value);

if (value) {
$obj.implementedVersion.show();
}

$this.hide();

$obj.implementedEdit.toggleAddEdit(value);
}
});
} else if (e.keyCode === keymap.ESC) {
e.preventDefault();

$(this).hide();
$obj.implementedEdit.show();

if ($obj.implementedVersion.text()) {
$obj.implementedVersion.show();
}
}
});

$.fn.toggleAddEdit = function(value) {
$(this).text(function() {
return value ? $(this).attr('data-l-edit') : $(this).attr('data-l-add');
}).prepend($('<i class="fa fa-fw"></i>').addClass(function() {
return value ? 'fa-pencil' : 'fa-plus-circle';
})).show();
};

/**
* Returns true if idea is a duplicate. Bit hacky.
*/
Expand All @@ -316,6 +360,14 @@
return href && href.indexOf('status=4') !== -1;
}

/**
* Returns true if idea is implemented. Bit hacky.
*/
function idea_is_implemented() {
var href = $obj.status.prev('a').attr('href');
return href && href.indexOf('status=3') !== -1;
}

function displayVoters(data) {

var upVoters = [],
Expand Down
24 changes: 13 additions & 11 deletions tests/controller/idea_controller_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,25 @@ public function controller_test_data()
{
return array(
array(1, '', '', false, null, null, 302), // non-ajax
array(2, 'delete', 'delete', true, true, '{}', 200), // ajax delete success (confirm fail)
array(2, 'delete', 'delete', true, false, 'NO_AUTH_OPERATION', 403), // ajax delete fail
array(2, 'delete', '', true, true, '{}', 200), // ajax delete success (confirm fail)
array(2, 'delete', '', true, false, 'NO_AUTH_OPERATION', 403), // ajax delete fail
array(2, 'delete', 'delete', true, true, 'trigger_error', 200), // ajax delete success (confirm true)
array(3, 'duplicate', 'set_duplicate', true, true, 'true', 200), // ajax set duplicate success
array(3, 'duplicate', 'set_duplicate', true, false, 'false', 200), // ajax set duplicate fail
array(3, 'duplicate', '', true, false, 'false', 200), // ajax set duplicate fail
array(4, 'removevote', 'remove_vote', true, true, 'true', 200), // ajax set title success
array(4, 'removevote', 'remove_vote', true, false, '"You do not have the necessary permissions to complete this operation."', 200), // ajax set title fail
array(4, 'removevote', '', true, false, '"You do not have the necessary permissions to complete this operation."', 200), // ajax set title fail
array(5, 'rfc', 'set_rfc', true, true, 'true', 200), // ajax set rfc success
array(5, 'rfc', 'set_rfc', true, false, 'false', 200), // ajax set rfc fail
array(6, 'status', 'set_status', true, true, 'true', 200), // ajax set status success
array(6, 'status', 'set_status', true, false, 'false', 200), // ajax set status fail
array(5, 'rfc', '', true, false, 'false', 200), // ajax set rfc fail
array(6, 'status', 'change_status', true, true, 'true', 200), // ajax set status success
array(6, 'status', '', true, false, 'false', 200), // ajax set status fail
array(7, 'ticket', 'set_ticket', true, true, 'true', 200), // ajax set ticket success
array(7, 'ticket', 'set_ticket', true, false, 'false', 200), // ajax set ticket fail
array(7, 'ticket', '', true, false, 'false', 200), // ajax set ticket fail
array(8, 'title', 'set_title', true, true, 'true', 200), // ajax set title success
array(8, 'title', 'set_title', true, false, 'false', 200), // ajax set title fail
array(8, 'title', '', true, false, 'false', 200), // ajax set title fail
array(9, 'vote', 'vote', true, true, 'true', 200), // ajax set title success
array(9, 'vote', 'vote', true, false, '"You do not have the necessary permissions to complete this operation."', 200), // ajax set title fail
array(9, 'vote', '', true, false, '"You do not have the necessary permissions to complete this operation."', 200), // ajax set title fail
array(10, 'implemented', 'set_implemented', true, true, 'true', 200), // ajax set implemented success
array(10, 'implemented', '', true, false, 'false', 200), // ajax set implemented fail
);
}

Expand All @@ -56,7 +58,7 @@ public function test_controller($idea_id, $mode, $callback, $is_ajax, $authorise
->will($this->returnValue(array('idea_id' => $idea_id, 'idea_author' => 2)));

// mock a result from each method called by the idea controller
$this->ideas->expects($this->any())
$this->ideas->expects(($callback !== '' ? $this->once() : $this->never()))
->method($callback)
->will($this->returnValue($authorised));

Expand Down
Loading