Redmine - Add "Spent Time" Field to Issues Display - redmine

How would I go about adding the "Spent Time" as a column to be displayed in the issues list?

Consolidating Eric and Joel's answers, this is what I needed to do to get a 'Spent time' column added to Redmine 1.0.3. Not sure if there's a better way to get the translation text added.
To give the new field a localised name, added to config/locales/en.yml around line 299 at the end of the field definitions:
field_spent_hours: Spent time
To add the new column, created lib/spent_time_query_patch.rb with content:
# Based on http://github.com/edavis10/question_plugin/blob/master/lib/question_query_patch.rb
require_dependency 'query'
module QueryPatch
def self.included(base) # :nodoc:
base.extend(ClassMethods)
# Same as typing in the class
base.class_eval do
unloadable # Send unloadable so it will not be unloaded in development
base.add_available_column(QueryColumn.new(:spent_hours))
end
end
module ClassMethods
unless Query.respond_to?(:available_columns=)
# Setter for +available_columns+ that isn't provided by the core.
def available_columns=(v)
self.available_columns = (v)
end
end
unless Query.respond_to?(:add_available_column)
# Method to add a column to the +available_columns+ that isn't provided by the core.
def add_available_column(column)
self.available_columns << (column)
end
end
end
end
To get the spent_time_query_patch above to actually load, created config/initializers/spent_time_query_patch.rb with content:
require 'spent_time_query_patch'
Query.class_eval do
include QueryPatch
end

You can also do this by adding the column at runtime. This will add the spent hours column without modifying the Redmine core. Just drop the following code into a file in lib/
Adapted from:
Redmine Budget Plugin
Redmine Question Plugin
require_dependency 'query'
module QueryPatch
def self.included(base) # :nodoc:
base.extend(ClassMethods)
# Same as typing in the class
base.class_eval do
unloadable # Send unloadable so it will not be unloaded in development
base.add_available_column(QueryColumn.new(:spent_hours))
end
end
module ClassMethods
unless Query.respond_to?(:available_columns=)
# Setter for +available_columns+ that isn't provided by the core.
def available_columns=(v)
self.available_columns = (v)
end
end
unless Query.respond_to?(:add_available_column)
# Method to add a column to the +available_columns+ that isn't provided by the core.
def add_available_column(column)
self.available_columns

Also, it would be cool, if the column "Spent time" was sortable.
After looking up the produced SQL, I just implemented the sortable feature this in this way:
base.add_available_column(QueryColumn.new(:spent_hours,
:sortable => "(select sum(hours) from time_entries where time_entries.issue_id = t0_r0)")
)
Replace the respective line. I just hope the issue_id column's name is always "t0_r0" ...
PS: You can find lots of examples in app/models/query.rb lines 122++
2-Digits Problem:
Unfortunatly, I had to hack one of the core files: app/helpers/queries_helper.rb
Around line 44, change this:
when 'Fixnum', 'Float'
if column.name == :done_ratio
progress_bar(value, :width => '80px')
else
value.to_s
end
into:
when 'Fixnum', 'Float'
if column.name == :done_ratio
progress_bar(value, :width => '80px')
elsif column.name == :spent_hours
sprintf "%.2f", value
else
value.to_s
end
EDIT: Using a patch instead manipulating the source Recently, we did an update of the redmine system, so the above mentioned Fix also was removed.
This time, we decided to implement that as a patch.
Open up any plugin (We created a plugin for our monkey-patch changes on core). open up vendor/plugins/redmine_YOURPLUGIN/app/helpers/queries_helper.rb
module QueriesHelper
def new_column_content(column, issue)
value = column.value(issue)
if value.class.name == "Float" and column.name == :spent_hours
sprintf "%.2f", value
else
__column_content(column, issue)
end
end
alias_method :__column_content, :column_content
alias_method :column_content, :new_column_content
end

This feature build in from 1.4.0 version

by using AgileDwarf plugin. You can have spent time & you can say for what you spent this time (developement - design -...)

Since no one answered, I just poked the source until it yielded results. Then I started a blog to explain how I did it.
Add spent time column to default issues list in Redmine

Related

How can I use regex to construct an API call in my Jekyll plugin?

I'm trying to write my own Jekyll plugin to construct an api query from a custom tag. I've gotten as far as creating the basic plugin and tag, but I've run into the limits of my programming skills so looking to you for help.
Here's my custom tag for reference:
{% card "Arbor Elf | M13" %}
Here's the progress on my plugin:
module Jekyll
class Scryfall < Liquid::Tag
def initialize(tag_name, text, tokens)
super
#text = text
end
def render(context)
# Store the name of the card, ie "Arbor Elf"
#card_name =
# Store the name of the set, ie "M13"
#card_set =
# Build the query
#query = "https://api.scryfall.com/cards/named?exact=#{#card_name}&set=#{#card_set}"
# Store a specific JSON property
#card_art =
# Finally we render out the result
"<img src='#{#card_art}' title='#{#card_name}' />"
end
end
end
Liquid::Template.register_tag('cards', Jekyll::Scryfall)
For reference, here's an example query using the above details (paste it into your browser to see the response you get back)
https://api.scryfall.com/cards/named?exact=arbor+elf&set=m13
My initial attempts after Googling around was to use regex to split the #text at the |, like so:
#card_name = "#{#text}".split(/| */)
This didn't quite work, instead it output this:
[“A”, “r”, “b”, “o”, “r”, “ “, “E”, “l”, “f”, “ “, “|”, “ “, “M”, “1”, “3”, “ “]
I'm also then not sure how to access and store specific properties within the JSON response. Ideally, I can do something like this:
#card_art = JSONRESPONSE.image_uri.large
I'm well aware I'm asking a lot here, but I'd love to try and get this working and learn from it.
Thanks for reading.
Actually, your split should work – you just need to give it the correct regex (and you can call that on #text directly). You also need to escape the pipe character in the regex, because pipes can have special meaning. You can use rubular.com to experiment with regexes.
parts = #text.split(/\|/)
# => => ["Arbor Elf ", " M13"]
Note that they also contain some extra whitespace, which you can remove with strip.
#card_name = parts.first.strip
#card_set = parts.last.strip
This might also be a good time to answer questions like: what happens if the user inserts multiple pipes? What if they insert none? Will your code give them a helpful error message for this?
You'll also need to escape these values in your URL. What if one of your users adds a card containing a & character? Your URL will break:
https://api.scryfall.com/cards/named?exact=Sword of Dungeons & Dragons&set=und
That looks like a URL with three parameters, exact, set and Dragons. You need to encode the user input to be included in a URL:
require 'cgi'
query = "https://api.scryfall.com/cards/named?exact=#{CGI.escape(#card_name)}&set=#{CGI.escape(#card_set)}"
# => "https://api.scryfall.com/cards/named?exact=Sword+of+Dungeons+%26+Dragons&set=und"
What comes after that is a little less clear, because you haven't written the code yet. Try making the call with the Net::HTTP module and then parsing the response with the JSON module. If you have trouble, come back here and ask a new question.

Google Finance currency converter issue in rails

I am working on Google currency converter but it's not working. It just redirects to:
http://finance.google.com:80/bctzjpnsun/converter?a=1&from=EUR&to=USD
or it's gives error 404 Not Found
This my code:
gem file:
gem 'money'
gem 'google_currency', '~> 3.4.1'
converter method
def self.exchange_to_USD annual_salary, currency
begin
mothly_salary = annual_salary / 12
if currency.present?
salary = Money.new(mothly_salary, currency).exchange_to(:USD).fractional
else
salary = mothly_salary
end
rescue Money::Bank::UnknownRate => e
salary = mothly_salary
rescue Exception => e
salary = mothly_salary
end
salary
end
application.rb file
require 'money'
require 'money/bank/google_currency'
# set the seconds after than the current rates are automatically expired
# by default, they never expire
Money::Bank::GoogleCurrency.ttl_in_seconds = 86400
# set default bank to instance of GoogleCurrency
Money.default_bank = Money::Bank::GoogleCurrency.new
Use eu_central_bank Instead.
We ended up replacing google_currency with eu_central_bank and it was very easy and worked great. It's part of RubyMoney so it should be well maintained. Basic replacement looks like this:
eu_central_bank = EuCentralBank.new
eu_central_bank.update_rates # TODO: Make this use a cache in a shared directory and just update it every day.
Money.default_bank = eu_central_bank
Definitely a good option to consider.
Google has depreciated that way of retrieving rates. Previously the "bctzjpnsun" link was an alternative way of getting them, but that was switched off recently (possibly on 01-Jun-2018).
You can find some alternative services here: https://stackoverflow.com/a/8391430/6038636

Globalize: How to show in the view the current locale information

I am currently having a bit of a problem with Globalize gem.
I explain the current situation:
I have a Model called Question. After creating it, without any data stored, I added the following lines to the model:
class Question < ActiveRecord::Base
translates :wording, :answer1, :answer2, :answer3, :answer4
end
Then, I created a migration to create the translations table
class CreateTranslationsTable < ActiveRecord::Migration
def up
Question.create_translation_table! :wording => :string, :answer1 => :string, :answer2 => :string, :answer3 => :string, :answer4 => :string
def end
def down
Question.drop_translation_table!
def end
My default locale is :en. After that I added some data.
If I go execute rails c and put the command Question.first.wording everything works fine.
Although when I execute in 'rails c' I18n.locale = :es and then I do Question.first.wording still displays the english text I put at the beginning.
I tried one thing which it seemed to help me is that I dropped all the translated columns (like specified in Globalize documentation after you migrated data. In my case I didn't have any data to migrate at the beginning though). After that I made a rollback (which got back the columns I deleted form the Question model), then executing Question.first.wording with I18n.locale = :es got it working. Which means that Question.first.wording returns nil.
After that, I implemented the 'Locale from Url Params' as specified in the Ruby on Rails guide
Which means the first URL param si the ':locale' param.
Now the current problem: The view still displays the information in English when it should display it in Spanish, since the URL I entered was http://localhost.com/es/questions/.
How can I make it to display in the view the Spanish information?
My mistake. I interpreted from the documentation that the the chunck of code (in application_controller.rb) that works for setting the url:
def default_url_options(options={})
{ locale: params[:locale] }
end
would actually set the 'I18n.locale' variable. What I did is the next to get around this (in application_controller.rb):
before_action :change_to_current_locale
def change_to_current_locale
I18n.locale = params[:locale]
end
That made it work.

Read MS Word .doc file with ruby and win32ole

I'm trying to read .doc file with ruby, I use win32ole library.
IT my code:
require 'win32ole'
class DocParser
def initialize
#content = ''
end
def read_file file_path
begin
word = WIN32OLE.connect( 'Word.Application' )
doc = word.activedocument
rescue
word = WIN32OLE.new( 'Word.Application' )
doc = word.documents.open( file_path )
end
word.visible = false
doc.sentences.each{ |x| #content = #content + x.text }
word.quit
#content
end
end
I kick off doc reading with DocParser.new.read_file('path/file.doc')
When I run this using rails c - I don't have any problems, it's working fine.
But when I run it using rails (e.g. after button click), once in a while (every 3-4 time) this code crashes with error:
WIN32OLERuntimeError (failed to create WIN32OLE object from `Word.Application'
HRESULT error code:0x800401f0
CoInitialize has not been called.):
lib/file_parsers/doc_parser.rb:14:in `initialize'
lib/file_parsers/doc_parser.rb:14:in `new'
lib/file_parsers/doc_parser.rb:14:in `rescue in read_file'
lib/file_parsers/doc_parser.rb:10:in `read_file'
lib/search_engine.rb:10:in `block in search'
lib/search_engine.rb:43:in `block in each_file_in'
lib/search_engine.rb:42:in `each_file_in'
lib/search_engine.rb:8:in `search'
app/controllers/home_controller.rb:9:in `search'
Rendered c:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-4.1.1/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.0ms)
Rendered c:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-4.1.1/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb (2.0ms)
Rendered c:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-4.1.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb (2.0ms)
Rendered c:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-4.1.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb (56.0ms)
Aditionaly, this code read doc file successfully, but RAILS CRASHES AFTER A FEW SECONDS:
look at this gist
What is my problem? How can I fix it?
Please, help!
Don't know the difference between rails c and rails, so I'll give some random advise.
First, it is a bad idea to run this in a webserver, each time Word is run on the server, so what happens if multiple users start using this at the same time ?
You'd better convert your .doc files to another format first like .rtf or .docx (a batch conversion ?) and then use other gems that don't require Word itself.
If you keep it like this, consider to not close word (remove the word.quit) buit only close the document itself, the instance will be picked up the next time by the WIN32OLE.connect
While testing you'de better keep word visible so that you can better see what is happening (errors ?).
I notice your path uses forward slashes while in this case backslashes are needed but since your code runs a few times before the error i suppose that is not the problem.
Hope this helps.
I upgrade my ruby from 1.9.3 to 2.0.0.
Now rails doesn't crashes and I have not problems with win23ole and reading old version MS Word documents.
I guess the problem was in memory usage - cause new ruby (>2.0.0) use new Garbage Collector.

Understanding Rails/Twitter On-click tweet on behalf of user

As preface, I've followed through some tutorials (i.e. Michael Hartl's) though I'm still fairly novice. Forgive any cloudy terminology.
I am trying to build a simple application in Rails 4 that does the following:
User logs into application (currently working with sign-in-with-twitter link and routing)
get "/auth/:provider/callback" => "sessions#create"
get "/signout" => "sessions#destroy", :as => :signout
Once <% if current_user %> is true, I have the view rendering a partial where there will be a list of simple buttons. When the user clicks a button I want the application to tweet on behalf of the current_user a preset string. Ideally, I'd do this all in ruby/rails.
These button functions are where I'm getting hung up. I've read a fistful of documents but there seem to be a lot of conflicting and old answers. Here's a quick list of the ones I think are closest, though not explicit about sending a tweet from a simple button/link in a view:
http://www.sitepoint.com/ruby-social-gems-twitter/
http://richonrails.com/articles/sending-a-tweet-to-twitter
Some call for controllers, a more robust oauth setup (which I have bundle installed and connected to the dev.twitter application, though not fleshed out beyond keys), and whatever else. It's got me turned around and I'm not yet good enough to synthesize all the information. Any help and direction would be great. Below are some other files in the app that might be helpful.
class SessionsController < ApplicationController
def create
auth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
session[:user_id] = user.id
redirect_to root_url, :notice => "Hi!"
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Bye!"
end
end
And omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twitter, '_priv', '_priv'
end
Eep! I'm the author of the second link (RichOnRails). Did you take a look at the example app included with the tutorial? It does almost exactly what you want. If the tweets are hard coded you could approach it in a couple of different ways. If you take a look at the tweets controller, you'll see it takes a parameter called 'message'. Any message passed to that create method will tweet as the current user.
def create
current_user.tweet(twitter_params[:message])
end
The easiest (but not necessarily best) way to adapt this to fit your needs is to have a form for each tweet, and do a hidden field with the message you wish to tweet. The button becomes a submit for that particular form (you can add remote: true if you want to keep the page from refreshing, then use a bit of javascript to update the UI elements). Hope this helps.