Skip to content

Instantly share code, notes, and snippets.

@bobbzorzen
Last active April 30, 2018 07:24
Show Gist options
  • Save bobbzorzen/cca44208ad03501bd5e36a7ea3c101c9 to your computer and use it in GitHub Desktop.
Save bobbzorzen/cca44208ad03501bd5e36a7ea3c101c9 to your computer and use it in GitHub Desktop.
A greasemonkey/tampermonkey script to fetch times from ticketeer and auto report to maconomy
// ==UserScript==
// @name Ticketeer Timesheet Integration Dev
// @namespace my.Home
// @version 1.0
// @description Makes your life better one friday at a time
// @author Tommy Svenningsson
// @grant none
// @match https://ter.istone.com/cgi-bin/Maconomy/*
// @require https://code.jquery.com/jquery-3.1.1.min.js
// ==/UserScript==
var apiKey = 'xxxx';
var user = '[email protected]';
var pass = 'xxxx';
var debug = false;
var ticketeerTimers, doc, weekDates, addedTimeIds;
window.onload = function(){
if (apiKey === ""){return;}
checkDOMChange();
};
function checkDOMChange()
{
for (var i = 0; i < window.frames.length; i++) {
(function(frame) {
// called whenever a frame is loaded or reloaded
if(frame.getAttribute("name") == "componentframe"){
doc = $(frame.contentDocument || frame.contentWindow.document);
scrapeDates(frame);
}
})(window.frames[i].frameElement);
}
}
function findRow(timer){
var row = false;
doc.find("#timeSheetTable tbody").children().each(function(){
var rowFavourite = $(this).find("input[title='"+timer.board_name+"']");
var rowDescription = $(this).find("input[title='"+timer.task_name+"']");
if(rowFavourite.length && rowDescription.length){
row = $(this);
}
});
return row;
}
function scrapeDates(frame){
var timeTable = doc.find("#timeSheetTable");
var datePicker = doc.find("#calendar");
datePicker.bind("DOMSubtreeModified",function(){
if(datePicker.find("span.selected")[0]){
var startDate = datePicker.find("span.selected span").attr("onclick").match(/.*?(\d+\.\d+\.\d+).*?/)[1].replace(/[.]/g,"-");
var endDate = datePicker.find("span.selected").parent().siblings(".days").last().find(".clickable").attr("onclick").match(/.*?(\d+\.\d+\.\d+).*?/)[1].replace(/[.]/g,"-");
loadTimers(startDate, endDate);
weekDates = getDates(new Date(startDate), new Date(endDate));
}
});
}
function loadTimers(startDate, endDate){
$.ajax ( {
type:'POST',
url:'https://www.ticketeer.se/api/get_time_report',
dataType:'json',
data:{key:apiKey, fromDate:startDate, toDate:endDate},
beforeSend: function (xhr){
xhr.setRequestHeader("Authorization", "Basic " + btoa(user + ":" + pass));
},
success:function(data){
doc.find("#updateTimes").parent().parent().remove();
if (data.length > 0){
var hours = 0;
ticketeerTimers = sortJsonArray(data, "task_id");
$.each(data, function( index, timer ) {
hours += timer.hours;
});
var ticketeerButtonHTML = '<td class="button"><div><input type="button" id="updateTimes" value="Add '+hours+' hours from ticketeer"></div></td>';
doc.find(".innerArea .buttonsTop .button").parent().append(ticketeerButtonHTML);
doc.find("#updateTimes").on("click", function(){
$(this).prop('value', "Working, please don't touch anything");
$(this).prop('disabled', true);
addedTimeIds = new Array();
populateTimesheet(0,null);
});
}
}
});
}
function populateTimesheet(index, prevTaskId){
var timeSheet = doc.find("#timeSheetTable");
var newRowButton = timeSheet.find("th.rowAction .button");
var inputs, timer, arrPos, existingRow;
if(index < ticketeerTimers.length){
timer = ticketeerTimers[index];
arrPos = $.inArray(timer.date,weekDates);
existingRow = findRow(timer);
if(timer.task_id == prevTaskId){
echo("Adding time to same row");
inputs = doc.find("#timeSheetTable tr.selected").children();
echo(inputs);
if(inputs.length > 0){
$(inputs[6+arrPos]).find("input").val(timer.hours);
$(inputs[6+arrPos]).find("input").attr("title", timer.hours);
addedTimeIds.push(timer.id);
checkTimer(timer.id);
}
populateTimesheet(index+1, timer.task_id);
}else if(existingRow){
echo("Adding to another existing row");
inputs = existingRow.children();
if(inputs.length > 0){
var timeInput = $(inputs[6+arrPos]).find("input");
timeInput.focus();
var selectCheck = window.setInterval(function(){
if(timeInput.closest("tr").hasClass("selected")){
timeInput.val(timer.hours);
timeInput.attr("title", timer.hours);
addedTimeIds.push(timer.id);
checkTimer(timer.id);
populateTimesheet(index+1, timer.task_id);
timeInput.trigger("keypress");
clearInterval(selectCheck);
}
}, 100);
}
}else{
echo("Adding new row for task_id:"+timer.task_id);
newRowButton.trigger("click");
doc.one("focus", "input", function() {
var favouriteField = $(this);
echo(favouriteField);
if(favouriteField[0]){
favouriteField.attr("title",timer.board_name);
favouriteField.val(timer.board_name);
var e = $.Event('keypress');
e.which = 13;
setTimeout(function() {
favouriteField.trigger(e);
doc.one("DOMSubtreeModified","#timeSheetTable", function(){
setTimeout(function() {
var inputs = doc.find("#timeSheetTable tr.selected").children();
if(inputs.length > 0){
$(inputs[6+arrPos]).find("input").val(timer.hours);
$(inputs[6+arrPos]).find("input").attr("title", timer.hours);
$(inputs[17]).find("input").val(timer.task_name);
addedTimeIds.push(timer.id);
checkTimer(timer.id);
}
populateTimesheet(index+1,timer.task_id);
},100);
});
}, 100);
}
});
}
}else{
setTimeout(function() {
alert(addedTimeIds.length+' of '+ticketeerTimers.length+" entries successfully added!");
}, 100);
echo(addedTimeIds);
doc.find("#updateTimes").parent().parent().remove();
}
}
function checkTimer(timerId){
$.ajax ( {
type:'POST',
url:'https://www.ticketeer.se/api/check_timer',
dataType:'json',
data:{key:apiKey, timerId:timerId},
beforeSend: function (xhr){
xhr.setRequestHeader("Authorization", "Basic " + btoa(user + ":" + pass));
},
success:function(data){
echo(data);
}
});
}
function getFormatedDate(date) {
var dd = date.getDate();
var mm = date.getMonth()+1; //January is 0!
var yyyy = date.getFullYear();
if(dd<10){
dd='0'+dd;
}
if(mm<10){
mm='0'+mm;
}
var today = yyyy +'-'+ mm +'-'+ dd;
return today;
}
function getDates(startDate, stopDate) {
var dateArray = new Array();
var datePicker = doc.find("#calendar");
var currentDate = startDate;
var pos = 0;
while (currentDate <= stopDate) {
var currentTd = datePicker.find("span.selected").parent().siblings("td").eq(pos);
var isWorkday = currentTd.hasClass('days');
if(isWorkday){
dateArray[pos] = getFormatedDate(currentDate);
}else{
dateArray[pos] = null;
}
currentDate = currentDate.addDays(1);
pos ++;
}
return dateArray;
}
Date.prototype.addDays = function(days) {
var dat = new Date(this.valueOf());
dat.setDate(dat.getDate() + days);
return dat;
};
Date.prototype.reverseDays = function(days) {
var dat = new Date(this.valueOf());
dat.setDate(dat.getDate() - days);
return dat;
};
function echo(logString){
if(debug){
console.log(logString);
}
}
function sortJsonArray(arr, prop) {
arr = arr.sort(function(a, b) {
return (b[prop] > a[prop]) ? 1 : ((b[prop] < a[prop]) ? -1 : 0);
});
return arr;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment