Adding groups to Projects in Redmine - ruby

i'm working on this script -> http://www.redmine.org/plugins/default_members <- by Sajin Andrei
I've completely modified the hook to suite my needs, but i realized that it actually adds every single user that is member of the defined group.
what i want to do is, instead, add the entire group to the project, so that if i add anyone else to the same group i'll not have to update every project.
this is my code:
# Debuggin [Default: commented/disabled]
#require 'logger'
class DefmembersHook < Redmine::Hook::ViewListener
def controller_projects_new_after_save(context={ })
#log = Logger.new('/usr/local/share/redmine/log/plugin.log')
params = context[:params]
project = context[:project]
roles = Role.find_all_givable
setting_group = Setting.plugin_redmine_default_members[:group] ? Setting.plugin_redmine_default_members[:group] : 'Manager'
groups ||= setting_group.split(",")
groups.each do |gp|
#log.error "gp: #{gp}"
group = Group.find(:first, :conditions => ["LOWER(lastname) = ?", gp.to_s.downcase])
#log.error "group: #{group}"
users = User.active.in_group(group).all(:limit => 100)
users.each do |user|
if user[:lastname] != 'Admin' && user[:lastname] != 'Anonymous'
#log.error "inizio per #{user}"
rs = Role.find_by_name(group.to_s)
#log.error "rs: #{rs}"
m = Member.new(:user => user, :roles => [rs])
project.members << m
#log.error "fine per #{user}"
end
end
end
end
end
and is actually working as intended by Sajin Andrei, adding single users from a group.
i want to do something like this
m = Member.new(:group => group, :roles => [rs])
project.members << m
but it doesn't work (obviously)...
hope someone can help

found the solution:
# Modificata da CARLO RUGGIERO per RETINA
# Permette di aggiungere interi gruppi ad un progetto in automatico!
class DefmembersHook < Redmine::Hook::ViewListener
def controller_projects_new_after_save(context={ })
params = context[:params]
project = context[:project]
#roles = Role.find_all_givable
setting_group = Setting.plugin_redmine_default_members[:group] ? Setting.plugin_redmine_default_members[:group] : 'Manager'
groups ||= setting_group.split(",")
groups.each do |gp|
group = Group.find(:first, :conditions => ["LOWER(lastname) = ?", gp.to_s.downcase])
rs = Role.find_by_name(group.to_s)
project.members << Member.new(:principal => group, :roles => [rs])
end
end
end
the problem was that the :user tag only accepts user elements
changing it to :principal i've got it to work
m = Member.new(:principal => group, :roles => [rs])
project.members << m
hope that someone find this usefull

Related

How to use a variable from one method to other in a same class in Ruby?

I am new to Ruby. I have the below code in my controller.
Desired Behaviour:-
I want to display the validation error string on my views on edit page. So I am putting those errors in a variable. When validation fails then I want to use that variable in my edit method, so that I can display that on my edit page view.
Observed behavior:-
There is a variable #vpinerr in create method. I want to use that variable in edit method. I have tried to use the class variable (##vpinerr) and initialized it with an empty string (##vpinerr = "") then the value of this variable becomes empty in edit method.
require 'rho/rhocontroller'
require 'helpers/browser_helper'
class LeadController < Rho::RhoController
include BrowserHelper
# GET /Lead
def index
#leads = Lead.find(:all)
render :back => '/app'
end
# GET /Lead/new
def new
#lead = Lead.new
render :action => :new, :back => url_for(:action => :index)
end
def create
# Update
if Lead.find(#params['id'])
#lead = Lead.find(#params['id'])
# array of objects
#leadadd = LeadAddress.find(:all,
:conditions => {:parentKey => #lead.object}
)
#leadcon = LeadContact.find(:all,
:conditions => {:parentKey => #lead.object}
)
#hash of hashes
leadaddressArray = #params['leadaddress']
arr1 = #leadadd.count - 1
for i in 0..arr1
j=i.to_s
#leadaddHash = #leadadd[i]
leadaddressHash = leadaddressArray[j]
if leadaddressHash['removed'] == "1"
singleadd = LeadAddress.find(:first,
:conditions => {:object => leadaddressHash['object']}
)
singleadd.destroy if singleadd
else
#validation
vpin = leadaddressHash['pincode']
#validation check
if vpin =~ /^[[:digit:]]+$/
#leadaddHash.update_attributes(leadaddressHash) if #leadaddHash
else
err = 1
#vpinerr = "Pincode is invalid"
end
end
end
leadconArray = #params['leadcontact']
arr2 = #leadcon.count - 1
for k in 0..arr2
z=k.to_s
#leadconHash = #leadcon[k]
leadContact = leadconArray[z]
if leadContact['removed'] == "1"
singlecon = LeadContact.find(:first,
:conditions => {:object => leadContact['object']}
)
singlecon.destroy if singlecon
else
#leadconHash.update_attributes(leadContact) if #leadconHash
end
end
#lead.update_attributes(#params['lead']) if #lead
if err == 0
redirect :action => :index
else
redirect :action => :edit, :id => #lead.object, :vpin =>#vpinerr
end
else
# Create
err = 0
# validation
vlead = #params['lead']
vfirstname = vlead['firstname']
vlastname = vlead['lastname']
vage = vlead['age']
#validation check
if (vfirstname =~ /^[[:alpha:][:blank:]]+$/) and (vlastname =~ /^[[:alpha:][:blank:]]+$/) and (vage =~ /^[[:digit:]]+$/)
#lead = Lead.create(#params['lead'])
#key = #lead.object
else
err = 1
#basicerr = "Basic Details are invalid"
end
if #params['leadaddress']
leadaddressArray = #params['leadaddress']
arrcount = leadaddressArray.count
for i in 1..arrcount
j=(i-1).to_s
leadaddressHash = leadaddressArray[j]
#validation
vpin = leadaddressHash['pincode']
#validation check
if vpin =~ /^[[:digit:]]+$/
#leadAdd = LeadAddress.create(leadaddressHash)
#leadAdd.parentKey = #key
#leadAdd.save()
else
err = 1
#vpinerr = "Pincode is invalid"
end
end
end
if #params['leadcontact']
leadconArray = #params['leadcontact']
arrcount2 = leadconArray.count
for k in 1..arrcount2
h=(k-1).to_s
leadconHash = leadconArray[h]
#validation
vhome = leadconHash['home']
vmobile = leadconHash['mobile']
vemail = leadconHash['email']
#validation check
if (vhome =~ /^[[:digit:]]+$/) and (vmobile =~ /^[[:digit:]]+$/) and (vemail =~ /\A([\w+\-]\.?)+#[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i)
#leadcontact = LeadContact.create(leadconHash)
#leadcontact.parentKey = #key
#leadcontact.save()
else
err = 1
#contacterr = "Contact Details are invalid"
end
end
end
if err == 0
redirect :action => :index
else
redirect :action => :edit, :id => #lead.object
end
end
end
# GET /Lead/{1}
def show
#lead = Lead.find(#params['id'])
#leadadd = LeadAddress.find(:all,
:conditions => {:parentKey => #lead.object}
)
#leadcontact = LeadContact.find(:all,
:conditions => {:parentKey => #lead.object}
)
if #lead
render :action => :show, :back => url_for(:action => :index)
else
redirect :action => :index
end
end
# GET /Lead/{1}/edit
def edit
#lead = Lead.find(#params['id'])
#leadaddress = LeadAddress.find(:all,
:conditions => {:parentKey => #lead.object}
)
#leadcontact = LeadContact.find(:all,
:conditions => {:parentKey => #lead.object}
)
#vpinerr2 = #vpinerr
if #lead
render :action => :new, :back => url_for(:action => :index)
else
redirect :action => :index
end
end
end
Variables with a prepending # are considered as instance variables and are available in a class's instance. Your controller is a class and with every request, Rails instantiates a new controller instance. In that sense, when you make a request to the create action, a new instance is created and #vpinerr is set in the instance. When you redirect the user to the edit action, its a new request and a new controller instance is instantiated. Since the instances from create action and edit actions are different, you won't have the value of #vpinerr in the edit action.
You have alternatives.
Class-level variables.
Class-level variables are set on the class and are available in all instances. Any variable prepended with ## are class variables. Change to ##vpinerr everywhere instead of #vpinerr.
This would be wrong to use in your case because, you could want it to be different for each user but using class variable will keep the value for other users too until its changed. Read about class variables: http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby
Session variables.
Session variables are used to save variables within a session. They can be shared between controllers too. To set a session variable session[:vpinerr] = "Some error" and to use it, you can simple call session[:vpinerr].

Ruby: Rerunning a loop with different code if end criteria is met

I have this program I wrote to automate a task I have at work. This is my first attempt at programming, with zero experience or training so forgive any silly mistakes. (I removed the website and my username/password)
require "rubygems"
require "selenium-webdriver"
require "nokogiri"
browser = Selenium::WebDriver.for :firefox
wait = Selenium::WebDriver::Wait.new(:timeout => 15)
#loads to unassigned results page
browser.get "-----------------"
p browser.title
browser.find_element(name: "user[username]").send_keys "--------"
browser.find_element(name: "user[password]").send_keys "--------"
browser.find_element(name: "commit").click
p browser.title
browser.find_element(class_name: "status_notification").click
begin
browser.find_element(:xpath => ".//*[#id='sub_nav_content']/table/tbody/tr[2]/td[3]/a").click
table = wait.until {
element = browser.find_element(id: "possible_matched")
element if element.displayed?
}
if table
puts "Table Found"
else
puts "Table Error"
end
#creates an 2D array containing patient name, admit date and prints to screen
names = browser.find_elements(:xpath => ".//*[#id='possible_matched']/table/tbody/tr/td[1]")
name_array = []
names.each { |name| name_array << name.text}
admits = browser.find_elements(:xpath => ".//*[#id='possible_matched']/table/tbody/tr/td[5]")
admit_array = []
admits.each { |date| admit_array << date.text }
name_admit_array = name_array.zip(admit_array)
name_admit_array.each do |name, date|
puts "#{name}: #{date}"
end
#finds the location of the sub-array containing patient name and collection associated admit date
patient_name = browser.find_element(:xpath => ".//*[#id='dialog-modal-cancel-hl7-preview']/table/tbody/tr[2]/td[1]").text
collected_date = browser.find_element(:xpath => ".//*[#id='dialog-modal-cancel-hl7-preview']/table/tbody/tr[2]/td[4]").text
mo, da, yr = collected_date.split('/').map(&:to_i)
cd = [yr, mo, da]
bl = name_admit_array.each_with_index.select { |(name, date), i|
m, d, y = date.split('/').map(&:to_i)
dt = [y, m, d]
name.downcase == patient_name.downcase and (dt <=> cd)<0
}.map {|x, i| i }
# presses the button associated with the correct sub-array
blf = name_admit_array.values_at(*bl)
if bl.any?
bf = blf.rindex(blf.max) + 2
browser.find_element(:xpath => ".//*[#id='possible_matched']/table/tbody/tr[#{bf}]/td[6]/div/a").click
else
browser.find_element(:xpath => "html/body/div[6]/div[1]/a/span").click
end
end while bl.any?
puts "no name :("
So it runs the loop until there is nothing found in the array bl. What I want to do is have this loop run again but with the next link on the list of links. So at the beginning of the loop it should do browser.find_element(:xpath => ".//*[#id='sub_nav_content']/table/tbody/tr[3]/td[3]/a").clickinstead of browser.find_element(:xpath => ".//*[#id='sub_nav_content']/table/tbody/tr[2]/td[3]/a").click. Then is should run the rest of the loop in the same way. I want it to continue to increment tr[] each time the loop runs into br.any? => false.
you can create an array of xpaths, and run this code for each of them:
[
".//*[#id='sub_nav_content']/table/tbody/tr[3]/td[3]/a",
".//*[#id='sub_nav_content']/table/tbody/tr[2]/td[3]/a"
].each do |path|
begin
browser.find_element(:xpath => path).click
// etc....
end while bl.any?
end
I believe that more changes need to adjust your code reusable, depending on your needs

using hash within Regexp - Can't convert Regexp into Integer [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I have a rake task that is pretty simple and works as I expect.
task :qualify => :environment do
require 'classifier'
# encoding: utf-8
test = Skirt.where(:asin => "B007O9MXF0")
w = %w{ rayon wool cotton polyester nylon spandex}
a = test.first.content
b = test.first.title
c = a + b
w.each do |w|
if c[/#{w}/]
c = w
else
c
end
end
good ={}
skirt = Skirt.where(:quality => "Good")
skirt.each do |f|
good[f.content] = [f.quality]
end
bad = {}
skirt = Skirt.where(:quality => "Bad")
skirt.each do |f|
bad[f.content] = [f.quality]
end
classifier = Classifier::Bayes.new('Good', 'Bad')
good.each {|good| classifier.train_good "Good"}
bad.each {|bad| classifier.train_bad "Bad"}
puts classifier.classify(a),
c,
test.first.color,
a+b
end
Now I am trying to get something a little more complex, but using the exact same idea and it does not work.
See the code below:
desc "Import details"
task :import_clean => :environment do
require 'sucker'
require 'mechanize'
require 'nokogiri'
require 'open-uri'
require 'carrierwave'
require 'rmagick'
require 'csv'
# encoding: utf-8
skirt = Skirt.where(:quality => "Good")
good = {}
skirt_type = ""
skirt.each do |f|
content_title = f.content + f.title
good[content_title] = [f.quality]
end
bad = {}
skirt = Skirt.where(:quality => "Bad")
skirt.each do |f|
content_title = f.content + f.title
bad[content_title] = [f.quality]
end
classifier = Classifier::Bayes.new('Good', 'Bad')
good.each {|good| classifier.train_good "Good"}
bad.each {|bad| classifier.train_bad "Bad"}
request = Sucker.new(
:associate_tag => 'thenewoutpro-20',
:key => 'AKIAJXNLXYCBU3NJAIJQ',
:secret => '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',
:locale => :us)
request << {
"Operation" => "ItemSearch",
"SearchIndex" => "Apparel",
"Keywords" => ["women", "skirt"],
"ResponseGroup" => ["BrowseNodes"] }
rep = request.get
url = "#{rep.find('MoreSearchResultsUrl')}"
new_url = url[2, url.length-4]
agent = Mechanize.new
agent.get(new_url)
i = (0..47)
i.each do |i|
b = "#{i}"
item = "#result_" + b
doc = agent.page.search(item)
link = doc.css("a")[0]["href"]
asin = link[-10,10]
request2 = Sucker.new(
:associate_tag => 'thenewoutpro-20',
:key => 'KEY',
:secret => 'SECRET',
:locale => :us)
request2 << {
"Operation" => "ItemLookup",
"IdType" => "ASIN",
"ItemId" => asin,
"ResponseGroup" => ["Large"] }
response = request2.get
images = response.find('LargeImage').first.to_a
image_new = images[0].to_s
image = image_new[8, image_new.length-9]
color_string = response.find('Color')
color = color_string[6, color_string.length]
brand_string = response.find('Manufacturer')
brand = brand_string[5, brand_string.length]
content = response.find('Content')
title = response.find('Title')
combined = content + title
f = %w{ polyester rayon nylon cotton silk chiffon wool knit jersey viscose corduroy velvet lace }
s = %w{ pencil A-line mini maxi long pleated panel }
p = %w{ pettite 'plus size' maternity }
f.each do |f|
if combined[/#{f}/]
fabric = f
else
fabric = ""
end
end
s.each do |s|
a = combined[/#{s}/]
if a > 0
skirt_type = s
else
skirt_type = ""
end
end
p.each do |p|
if combined[/#{p}/]
size = p
else
size = "Regular"
end
end
quality = classifier.classify(combined)
Bottom.create!(
:asin => asin,
:title => response.find('Title'),
:price => response.find('FormattedPrice'),
:manufacturer => brand,
:content => response.find('Content'),
:color => color,
:fabric => fabric,
:size => size,
:skirt_type => skirt_type,
:images => image,
:link => link)
end
end
end
I get the following error when I try to run the rake: rake aborted!
can't convert Regexp into Integer
The part I don't understand is that the same portion of the code (using the hash within the Regexp to run over an array) is working just fine on rake task :qualify.
Any ideas?
Thanks!
combined = (content + title).to_s
in combined[regex], if combined is not a string, Ruby thinks you are accessing an Array and therefore expects regex to be an integer...

Loading users from Active Directory into a Rails 3.1 Active Record database

Update 11/30/11
I made some changes in the code snippet where I found errors. I am now successfully authenticating for sure, but am getting this error after attempting the ldap.search call:
<OpenStruct code = 1, message="Operations Error">
Using Rails 3.1.0 and ruby 1.9.2 on Windows Server 2008 R2
Original Message
I'm brand new to Ruby, rails and programming. I have an application that will have to authenticate to our Active Directory server while maintaining a list of users separate from AD.
I'm attempting to use net-ldap to establish the connection, search AD and load the users, but I get 0 results with each attempt to run.
I've put this together based on samples I've seen, but when I customize it to my company, it doesn't seem to work. Any ideas/critiques are most welcome.
thanks!
I've set this as a method in my User class model:
class User < ActiveRecord::Base
attr_accessible :username, :name, :email, :team, :office, :points_attributes
validates_presence_of :username, :name, :email
validates_uniqueness_of :username, :email
has_one :points
accepts_nested_attributes_for :points
def self.import_all
# initialization stuff. set bind_dn, bind_pass, ldap_host, base_dn and filter
ldap = Net::LDAP.new(:host => "dc.mycompany.com", :port => 389)
if ldap.bind(:method => :simple, :username => "username#mycompany.com", :password => "secret")
else
p ldap.get_operation_result
end
begin
# Build the list
filter = Net::LDAP::Filter.eq("displayName", "J*")
attrs = ["givenName", "sn", "physicalDeliveryOfficeName", "sAMAccountName"]
records = new_records = 0
ldap.search(:base => "DC=mycompany,DC=com", :attributes => attrs, :filter => filter, :return_result => false) do |entry|
name = entry.givenName.to_s.strip + " " + entry.sn.to_s.strip
username = entry.sAMAccountName.to_s.strip
email = entry.sAMAccountName.to_s.strip + "#mycompany.com"
office = entry.physicalDeliveryOfficeName.to_s.strip
user = User.find_or_initialize_by_username :name => name, :username => username, :email => email, :office => office
if user.new_record?
user.save
Points.find_or_create_by_user_id(user.id)
new_records = new_records + 1
else
user.touch
end
records = records + 1
end
p ldap.get_operation_result
logger.info( "LDAP Import Complete: " + Time.now.to_s )
logger.info( "Total Records Processed: " + records.to_s )
logger.info( "New Records: " + new_records.to_s )
end
end
end
It turns out that the error I'm getting is due to some of the attributes I'm searching for not existing on all the users under the tree I'm looking at.
Thanks to any that looked at this, but I believe I can move on to resolving how to handle entries without those attributes.

Ruby 1.9: turn these 4 arrays into hash of key/value pairs

I have four arrays that are coming in from the client. Let's say that there is an array of names, birth dates, favorite color and location. The idea is I want a hash later where each name will have a hash with respective attributes:
Example date coming from the client:
[name0, name1, name2, name3]
[loc0, loc1]
[favcololor0, favcolor1]
[bd0, bd1, bd2, bd3, bd4, bd5]
Output I'd like to achieve:
name0 => { location => loc0, favcolor => favcolor0, bd => bd0 }
name1 => { location => loc1, favcolor => favcolor1, bd => bd1 }
name2 => { location => nil, favcolor => nil, bd => bd2 }
name3 => { location => nil, favcolor => nil, bd => bd3 }
I want to have an array at the end of the day where I can iterate and work on each particular person hash.
There need not be an equivalent number of values in each array. Meaning, names are required.. and I might receive 5 of them, but I only might receive 3 birth dates, 2 favorite colors and 1 location. Every missing value will result in a nil.
How does one make that kind of data structure with Ruby 1.9?
I would probably do it like this
# assuming names, fav_colors, birth_dates, and locations are your arrays
name_collection = {}
names.zip(birth_dates, fav_colors, locations) do |name, birth_date, fav_color, location|
name_collection[name] = { :birth_date => birth_date,
:fav_color => fav_color,
:location => location }
end
# usage
puts name_collection['jack'][:fav_color] # => 'blue'
A small class to represent a person
class Person
attr_accessor :name, :color, :loc, :bd
def initialize(args = {})
#name = args[:name]
#color = args[:color]
#loc = args[:loc]
#bd = args[:bd]
end
def pp()
puts "*********"
puts "Name: #{#name}"
puts "Location: #{#loc}"
puts "Birthday: #{#bd}"
puts "Fav. Color: #{#color}"
puts "*********"
end
end
another to represent people, which is mainly just a listing of Persons.
class People
attr_accessor :list_of_people
def initialize()
#list_of_people = {}
end
def load_people(names, locations, favcolors, birthdates)
names.each_with_index do |name, index|
#list_of_people[name] = Person.new(:name => name, :color => favcolors[index], :loc => locations[index], :bd => birthdates[index])
end
end
def pp()
#list_of_people.each_pair do |key, value|
value.pp()
end
end
end
I threw in a pretty print function for each so you can see their data. With a starting point like this it will be really easy to modify and add methods that do all sorts of useful things.
if __FILE__ == $0
names = ["name0", "name1", "name2", "name3"]
locs = ["loc0","loc1"]
favcolors = ["favcolor0", "favcolor1"]
bds = ["bd0","bd1","bd2","bd3","bd4"]
a = People.new()
a.load_people(names,locs,favcolors,bds)
a.pp()
end
I think the kind of data structure you're looking for is -ahem- a Struct.
# setup data
names = %w(name0 name1 name2 name3)
locations = %w(loc0 loc1)
colors = %w(favcololor0 favcolor1)
bd = %w(bd0 bd1 bd2 bd3 bd4 bd5)
# let's go
Person = Struct.new( :name, :location, :fav_color, :bd )
all_persons = names.zip( locations, colors, bd ).map{|p| Person.new( *p)}
# done
puts all_persons
someone= all_persons.find{|p| p.name == "name1"}
puts someone.location unless someone.nil?

Resources