# Type: Input # Category: Aliases # Description: Allows to select which custom field will be an alias for issue # Author: Andriy Lesyuk new Orangutan::Context( response => sub { my ($context, $user, $message) = @_; my $regexp; my @result = ( ); # New alias my $customfields = $main::config->Get('redmine', '_customfields_regexp'); if ($customfields) { $regexp = '(?:Use )?(?:(?:(?:the|a) )?values? of )?(?:(?:(?:the|a) )?(?:custom )?field )?'; $regexp .= '["\']?('.$customfields.')["\']? '; $regexp .= '(?:as|is) (?:(?:the|an?) )?(?:custom field )?alias(?:es)?(?: for (?:(?:the|an?) )?issue(?: (?:id|number))?s?)?!*\.*'; if ($message =~ /^$regexp$/i) { push(@result, 1); push(@result, $1); } } # Show alias if (scalar @result == 0) { my @regexps = ( '(?:Show )?(?:(?:(?:the|a) )?values? of )?(?:what|which) (?:(?:custom )?field )?(?:is|are)(?: used as)? '. '(?:(?:the|an?) )?alias(?:es)? for (?:(?:the|an?) )?issue(?: (?:id|number))?s?\?*!*\.*', '(?:(?:Show|print) )?custom field alias!*\.*' ); foreach my $regexp (@regexps) { if ($message =~ /^$regexp$/i) { push(@result, 2); } } } # Remove alias if (scalar @result == 0) { @regexps = ( '(?:Do(?:n\'t| not)|stop) us(?:e|ing) (?:(?:(?:the|a) )?values? of )?(?:any )?(?:custom )?field as '. '(?:(?:the|an?) )?alias(?:es)? for (?:(?:the|an?) )?issue(?: (?:id|number))?s?!*\.*', '(?:Remove|delete|drop|clear) custom field alias!*\.*' ); foreach my $regexp (@regexps) { if ($message =~ /^$regexp$/i) { push(@result, 3); } } } return @result; }, handler => sub { my ($context, $user, $item, $fieldname) = @_; if ($item == 1) { my $customfield = $main::query->GetCustomFieldName($fieldname); if ($customfield) { if ($customfield->{'field_format'} eq 'string') { if ($customfield->{'regexp'}) { $customfield->{'regexp'} =~ s/^\^//g; $customfield->{'regexp'} =~ s/\$$//g; if ($customfield->{'min_length'} || $customfield->{'max_length'}) { $customfield->{'_regexp'} = '.'; $customfield->{'_regexp'} .= '{'; if ($customfield->{'min_length'}) { $customfield->{'_regexp'} .= $customfield->{'min_length'}; } $customfield->{'_regexp'} .= ','; if ($customfield->{'max_length'}) { $customfield->{'_regexp'} .= $customfield->{'max_length'}; } $customfield->{'_regexp'} .= '}'; } } else { $user->SendMessage([ 'Custom field used as an alias for issue must have regexp defined!', 'Ask administrator to define regexp for this custom field first!..', "Can't use this custom field - it does not have regexp!" ]); return; } } elsif ($customfield->{'field_format'} eq 'int') { if ($customfield->{'regexp'}) { $customfield->{'regexp'} =~ s/^\^//g; $customfield->{'regexp'} =~ s/\$$//g; } $customfield->{'_regexp'} = '[0-9]'; if ($customfield->{'min_length'} || $customfield->{'max_length'}) { $customfield->{'_regexp'} .= '{'; if ($customfield->{'min_length'}) { $customfield->{'_regexp'} .= $customfield->{'min_length'}; } $customfield->{'_regexp'} .= ','; if ($customfield->{'max_length'}) { $customfield->{'_regexp'} .= $customfield->{'max_length'}; } $customfield->{'_regexp'} .= '}'; } else { $customfield->{'_regexp'} .= '+'; } $customfield->{'_regexp'} .= '}'; } elsif ($customfield->{'field_format'} eq 'list') { my $values = $main::query->GetCustomFieldList($customfield->{'id'}); if (scalar @{$values} > 0) { if (scalar @{$values} < 1024) { $customfield->{'_regexp'} = ''; for (my $i = 0; $i < scalar @{$values}; $i++) { if ($i > 0) { $customfield->{'_regexp'} .= '|'; } $customfield->{'_regexp'} .= quotemeta(@{$values}[$i]); } } else { $user->SendMessage([ 'Cannot load such a big list of possible values...', "Hm... It's too huge!.. Too many possible values!", 'Wow! Too many possible values!..' ]); return; } } else { $user->SendMessage([ "The field must have possible values defined!", 'This custom field has no possible values!..', 'I need this field to have possible values!' ]); return; } } else { my $format = Orangutan::Context::Random( "Field used as an alias for issue must be of 'string' or 'int' type!", "The field must be of 'string' or 'int' type!..", "This field has type '%s'... Can't use it!.." ); $user->SendMessage(sprintf($format, $customfield->{'field_format'})); return; } } else { $user->SendMessage([ 'Perhaps you made a mistake in the name.. I cannot find such custom field!', "Can't find issue custom field with such name...", 'There is no such custom field!' ]); return; } my $ratio = $main::query->GetCustomFieldRatio($customfield->{'id'}); if ($ratio > 90) { $user->SetOption('CustomFieldAlias', $customfield->{'name'}); $context->SetField('field', $customfield); $user->SendMessage([ "Ok. I'll do this.", 'Ok. I will!..', 'Got it!' ]); } elsif ($ratio > 0) { my $format = Orangutan::Context::Random( 'I need to "map" value of this field to issue ID... But only %.02f%% of values point to a single issue.', 'There would be too many misunderstandings if I used this field...', "Can't use this field - only %.02f%% of values are unique..." ); $user->SendMessage(sprintf($format, $ratio)); } else { $user->SendMessage([ 'There is no value of this field which points to a single issue!..', 'A value of this field should point to a single issue.', 'The field does not look usable... Sorry!' ]); } } elsif ($item == 2) { my $customfield = $context->GetField('field'); if ($customfield) { my $format = Orangutan::Context::Random( 'Custom field "%s" is used as an alias for issue ID...', 'You told me to use "%s"...', 'I\'m using "%s"...' ); $user->SendMessage(sprintf($format, $customfield->{'name'})); } else { $user->SendMessage([ "I don't use any custom field as alias for issue...", 'No custom field is used.' ]); } } else { my $customfield = $context->GetField('field'); if ($customfield) { $user->ClearOption('CustomFieldAlias'); $context->UnsetField('field'); my $message = Orangutan::Context::Random('Ok... ', 'I see. ', 'Got it! '); $message .= Orangutan::Context::Random( "Won't use any custom field.", "Won't do this any more..." ); $user->SendMessage($message); } else { $user->SendMessage([ "Hm.. I don't use any custom field as alias for issue...", "But I don't...", "I don't!.." ]); } } }, init => sub { my ($context) = @_; foreach my $username ($main::users->GetUsers) { my $user = $main::users->GetUser($username); my $customfieldalias = $user->GetResponse($context->GetID); if ($customfieldalias) { my $fieldname = $user->GetOption('CustomFieldAlias'); if ($fieldname) { my $customfield = $main::query->GetCustomFieldName($fieldname); if ($customfield) { if ($customfield->{'field_format'} eq 'string') { if ($customfield->{'regexp'}) { $customfield->{'regexp'} =~ s/^\^//g; $customfield->{'regexp'} =~ s/\$$//g; if ($customfield->{'min_length'} || $customfield->{'max_length'}) { $customfield->{'_regexp'} = '.'; $customfield->{'_regexp'} .= '{'; if ($customfield->{'min_length'}) { $customfield->{'_regexp'} .= $customfield->{'min_length'}; } $customfield->{'_regexp'} .= ','; if ($customfield->{'max_length'}) { $customfield->{'_regexp'} .= $customfield->{'max_length'}; } $customfield->{'_regexp'} .= '}'; } $customfieldalias->SetField('field', $customfield); } } elsif ($customfield->{'field_format'} eq 'int') { if ($customfield->{'regexp'}) { $customfield->{'regexp'} =~ s/^\^//g; $customfield->{'regexp'} =~ s/\$$//g; } $customfield->{'_regexp'} = '[0-9]'; if ($customfield->{'min_length'} || $customfield->{'max_length'}) { $customfield->{'_regexp'} .= '{'; if ($customfield->{'min_length'}) { $customfield->{'_regexp'} .= $customfield->{'min_length'}; } $customfield->{'_regexp'} .= ','; if ($customfield->{'max_length'}) { $customfield->{'_regexp'} .= $customfield->{'max_length'}; } $customfield->{'_regexp'} .= '}'; } else { $customfield->{'_regexp'} .= '+'; } $customfield->{'_regexp'} .= '}'; $customfieldalias->SetField('field', $customfield); } elsif ($customfield->{'field_format'} eq 'list') { my $values = $main::query->GetCustomFieldList($customfield->{'id'}); if ((scalar @{$values} > 0) && (scalar @{$values} < 1024)) { $customfield->{'_regexp'} = ''; for (my $i = 0; $i < scalar @{$values}; $i++) { if ($i > 0) { $customfield->{'_regexp'} .= '|'; } $customfield->{'_regexp'} .= quotemeta(@{$values}[$i]); } $customfieldalias->SetField('field', $customfield); } } } if (!$customfieldalias->GetField('field')) { $main::logger->Log("could not find custom field: %s", $fieldname); $user->ClearOption('CustomFieldAlias'); } } } } }, filter => sub { my ($context, $user, $message) = @_; my $customfield = $context->GetField('field'); if ($customfield) { my $regexp = $customfield->{'regexp'} ? $customfield->{'regexp'} : $customfield->{'_regexp'}; my $regexp2 = $customfield->{'regexp'} ? $customfield->{'_regexp'} : undef; my %matched = ( ); while (${$message} =~ /\b($regexp)\b/gi) { my $match = $1; if (!defined($regexp2) || ($match =~ /\b$regexp2\b/gi)) { $matched{$match}++; } } if ((scalar keys %matched > 0) && ($main::query->GetCustomFieldValues($customfield->{'id'}, keys %matched) > 0)) { my %aliases = ( ); while (defined(my $value = $main::query->Next)) { if (defined($aliases{$value->{'value'}})) { if (ref $aliases{$value->{'value'}} ne 'ARRAY') { $aliases{$value->{'value'}} = [ '#'.$aliases{$value->{'value'}} ]; } push(@{$aliases{$value->{'value'}}}, '#'.$value->{'customized_id'}); } else { $aliases{$value->{'value'}} = $value->{'customized_id'}; } } my $count = 0; foreach my $alias (keys %aliases) { if (ref $aliases{$alias} eq 'ARRAY') { my $format = Orangutan::Context::Random( "Can't understand which issue %s stands for: %s... :S", "Not replacing %s - can't choose one of: %s...", 'Leaving %s as it is... Too many issues: %s!' ); $user->SendMessage(sprintf($format, $alias, join(', ', @{$aliases{$alias}}))); } elsif (${$message} =~ s/\b$alias\b/#$aliases{$alias}/gi) { $count++; } } return $count; } } return 0; }, help => [{ title => 'How can I create a custom field alias?', question => [ '^(?:How )?(?:(?:can|do) I |to )specify (?:(?:(?:the|a) )?values? of )?(?:what|which) (?:custom )?field '. '(?:to use|(?:should|must) be used) as (?:(?:the|an?) )?alias(?:es)? for '. '(?:(?:the|an?) )?issue(?: (?:id|number))?\?*!*\.*$', '^(?:How )?(?:(?:can|do) I |to )(?:create|set|specify|define) (?:(?:the|a) )?custom field alias(?:es)?\?*!*\.*$' ], answer => "It can be quite complicated to remember issue numbers. ". "For this aliases where introduced. ". "However aliases are set by users and most likely they will differ for each user. ". "Due to this it will become impossible to refer to issues on meetings etc. ". "Luckily Orangutan supports custom field based aliases... ". "You tell Orangutan values of which custom field should be used as aliases for issue numbers ". "and you can specify these aliases globally that is for all users.\n". "This can be done using queries like:\n". " o Use values of field \"Special ID\" as aliases for issue\n". " o Use \"Alternative Name\" as alias for issue ID\n". " o Use custom field \"Name\" as alias for issue\n". " o Use \"SJ ID\" as custom field alias\n". "However not every custom field can be used here... ". "Such custom field should meet the following requirements:\n". " o Be of 'string', 'int' or 'list' type\n". " o Have a strict regexp (except for 'list' type)\n". " o For 'list' type there should not be many list items\n". " o Each value should correspond to a single issue\n". " o It is better if it has min_length and max_length defined\n". "Using invalid custom field can dramatically slow down work of Orangutan ". "so be very careful when selecting it.", weight => 1250 }, { title => 'How can I check custom field alias?', question => [ '^(?:How )?(?:(?:can|do) I |to )(?:check|see|know|get) (?:(?:(?:the|a) )?values? of )?(?:what|which) '. '(?:custom )?field (?:is|are)(?: used as)? (?:(?:the|an?) )?alias(?:es)? for '. '(?:(?:the|an?) )?issue(?: (?:id|number))?\?*!*\.*$', '^(?:How )?(?:(?:can|do) I |to )(?:check|see|know|get) (?:(?:the|a) )?custom field alias(?:es)?\?*!*\.*$' ], answer => "Forgot what custom field did you select as alias for issue? No problem - ask Orangutan!\n". "Here are samples:\n". " o Values of what custom field are used as aliases for issue numbers?\n". " o Which custom field is used as alias for issue?\n". " o Show custom field alias", weight => 1260 }, { title => 'How can I remove a custom field alias?', question => [ '^(?:How )?(?:(?:can|do) I |to )(?:specify|tell|select) not to use (?:(?:(?:the|a) )?values? of )?any (?:custom )?field as '. '(?:(?:the|an?) )?alias(?:es)? for (?:(?:the|an?) )?issue(?: (?:id|number))?\?*!*\.*$', '^(?:How )?(?:(?:can|do) I |to )(?:remove|delete|drop|clear) (?:(?:the|a) )?custom field alias(?:es)?\?*!*\.*$' ], answer => "Added some custom field alias by mistake? Just remove it!\n". "Ask Orangutan something like:\n". " o Don't use any custom field as alias for issue ID!\n". " o Remove custom field alias\n", weight => 1270 }], weight => sub { my ($context, $user) = @_; my $customfields = $main::config->Get('redmine', '_customfields_regexp'); if ($customfields) { return ( undef, 0, 0 ); } else { return ( undef, undef, undef ); } }, copy => 1 ); # kate: syntax perl