astro-panda / clockify.net Goto Github PK
View Code? Open in Web Editor NEWClockify C# Client
License: MIT License
Clockify C# Client
License: MIT License
Currently the method FindAllTimeEntriesForUserAsync accepts start as parameter (as well as end). the parameter ist a DateTimeOffset that has to be a format mentioned in https://stackoverflow.com/questions/114983/given-a-datetime-object-how-do-i-get-an-iso-8601-date-in-string-format
Otherwise a datetimeoffset as start or end does not work because it only uses tostring to serialize the parameter
Hi there
Is there a reason, why GetSummaryReportAsync is made private?
Thanks
The client library class TimeEntryDtoImpl
contains a List<string> TagIds
and a string TaskId
.
The Clockify.me API returns an TimeEntryDtoImpl
object that contains a list of tags objects List<TagDto> TagIds
(or an object very similar to a TagDto) as well as a TaskDto Task
object (or an object very similar to a TaskDto).
Example Response from _clockifyClient.FindAllTimeEntriesForUserAsync
:
[
{
"id": "<removed_for_privacy>",
"description": "test description",
"tags": [
{
"id": "<removed_for_privacy>",
"name": "Testing",
"workspaceId": "<removed_for_privacy>",
"archived": false
}
],
"user": null,
"billable": false,
"task": {
"id": "<removed_for_privacy>",
"name": "AAAATESTTASK",
"projectId": "<removed_for_privacy>",
"assigneeIds": [],
"assigneeId": "",
"estimate": "PT0S",
"status": "ACTIVE",
"duration": "PT3H"
},
"project": {
"id": "<removed_for_privacy>",
"name": "AAAATEST PROJECT",
"hourlyRate": {
"amount": 0,
"currency": "USD"
},
"clientId": "<removed_for_privacy>",
"workspaceId": "<removed_for_privacy>",
"billable": false,
"memberships": [
{
"userId": "<removed_for_privacy>",
"hourlyRate": null,
"targetId": "<removed_for_privacy>",
"membershipType": "PROJECT",
"membershipStatus": "ACTIVE"
}
],
"color": "#C106E4",
"estimate": {
"estimate": "PT0S",
"type": "AUTO"
},
"archived": false,
"duration": "PT3H",
"clientName": "AAAAAATestClient",
"note": "",
"template": false,
"public": false
},
"timeInterval": {
"start": "2020-05-19T10:15:36Z",
"end": "2020-05-19T13:15:36Z",
"duration": "PT3H"
},
"workspaceId": "<removed_for_privacy>",
"hourlyRate": null,
"userId": "<removed_for_privacy>",
"customFieldValues": null,
"projectId": "<removed_for_privacy>",
"isLocked": false
}
]
The member types for the TimeEntryDtoImpl
would have to be updated to match the current Clockify.me API.
Let me know if there's anything I can do for ya!
Summary:
Some tests are are failing on the first run of the test. But after rerunning them they will pass.
Steps to repoduce:
Run all the tests. After they finnish run only the tests that didn't pass.
Expected Result:
Test to pass.
Actual Result:
Test are failing. And for them to pass they need to be rerun.
It should be
public Task DeleteTimeEntryAsync(string workspaceId, string timeEntryId)
"-Also, could you add the variable clientid/client_name to the TimeEntryDtoImpl?"
I tried to "push" some new features without success.
def get_reports_summary(start, end):
"""Send a "deprecated" request to clockify to sent summary report.
The start date will start 00:00:00 on the given start and will end 23:59:59
on the given end date. Time will be handled automatically.S
:param start: The date when the report should start with the report in format yyyy-MM-dd
:param end: The date when the report should end with the report in format yyyy-MM-dd
:return: tuple holding engineers, total amount of all projects and detailed information sorted for each project
"""
url = base_url_api0 + "/workspaces/{}/reports/summary/".format("5e309aa8b128ac31f259ee0d")
data = {
"startDate":f"{start}T00:00:00.000Z",
"endDate": f"{end}T23:59:59.999Z",
"me": "false",
"userGroupIds": [],
"userIds": [],
"projectIds": [],
"clientIds": [],
"taskIds": [],
"tagIds": [],
"billable": "BOTH",
"includeTimeEntries": True,
"zoomLevel": "month",
"description": "",
"archived": "Active",
"roundingOn": False #rounding is only working a upgraded version which needs to be paied. No effect on current plan
}
response = requests.post(url, data=json.dumps(data), headers=headers)
response.encoding = 'utf-8'
# print(response.text)
rjs = response.json()
projects = set()
engineers = set()
registers = []
for entry in rjs['timeEntries']:
username = entry['user']['name']
description = entry['description']
clientName = entry['clientName']
date = entry['timeInterval']['start'] # 2019-07-18T09:06:00Z
date = dateutil.parser.parse(date) # datetime
enddate = dateutil.parser.parse(entry['timeInterval']['end'])
hourlyRate = entry['hourlyRate']['amount']
duration = hours_from_duration(entry['timeInterval']['duration'])
if not isinstance(duration, float):
continue # duration is None when the clock is running, so ignore it
try:
project = entry['project']['name']
except TypeError: # TypeError: 'NoneType' object is not subscriptable
continue
projects.add(project)
engineers.add(username)
registers.append((project, username, duration, hourlyRate, description, date, enddate, clientName))
return list(projects), list(engineers), registers, rjs['totalBillable']`
Currently updating project estimates and project memberships is not supported. It would be very useful for these routes to be added.
Hi,
thanks for your implementation of the clockify client.
I was trying to implement a redmine bridge which filters entries by a to-redmine
tag and processes them.
Unfortunately the client doesn't implement the tags
parameter yet (https://clockify.me/developers-api#tag-Time-entry).
TL;DR I'm seeking someone to transfer this repository and nuget package.
Hey!
I have been maintaining and developing Clockify.Net for over 4 years now.
Since then API has changed so much that I can't keep up with the changes. I'm just tired of breaking changes and inconsistency.
Now I'm looking for someone ready to take that burden from me. I've started large refactoring on feature/cleanup
branch. You can continue it or choose your own path.
I've found a few problems with Clockify API:
And I can even find more.
If you want to take this repo from me contact me here or on my email [email protected]
As the method can only return unhydrated time entries (TimeEntryDtoImpl) , the parameter "hydrated" is useless.
Suggestion: Separate method for hydrated time entries, which uses appropriate method for the use time entry queries (ClockifyClient.FindAllHydratedTimeEntriesForUserAsync) and returns HydratedTimeEntryDtoImpl
Hi there,
I did write a short program to fetch my summary report from Clockify.
As a SummaryReportRequest
I am using this:
SummaryReportRequest summaryReportRequest = new()
{
DateRangeStart = new DateTime(2022, 2, 7),
DateRangeEnd = new DateTime(2022, 2, 13),
SummaryFilter = new SummaryFilterDto()
{
Groups = new List<GroupType>()
{
GroupType.DATE,
GroupType.TAG
},
SortColumn = SortColumnType.GROUP
},
ExportType = ExportType.JSON
};
var reportResponse = await clockifyClient.GetSummaryReportAsync(workspace.Id, summaryReportRequest);
The reportResponse
is not successful and gives ErrorMessage: Unexpected character encountered while parsing value: [. Path 'groupOne[0].children[0]._id', line 1, position 185.
The error's position and the example might slightly differ, as I did not paste the exact JSON response (truncated it a bit).
When looking at the JSON response, I have something like this:
{
"totals": [{
"_id": "",
"totalTime": 39784,
"entriesCount": 45,
"totalAmount": null
}],
"groupOne": [{
"duration": 39784,
"_id": "2022-02-07",
"name": "2022-02-07",
"children": [
{
"duration": 24669,
"_id": ["61aa2fa49e0fb0338dac807b"],
"name": "Project A",
"nameLowerCase": "project a"
}, {
"duration": 10940,
"_id": ["61aa2ff01799d3570fc4ab44"],
"name": "Project B",
"nameLowerCase": "project B"
}, {
"duration": 1184,
"_id": ["61aa31531799d3570fc4c648"],
"name": "Internal meeting",
"nameLowerCase": "internal meeting"
}, {
"duration": 2991,
"_id": ["61aa305d9e0fb0338dac8d05"],
"name": "Support tag",
"nameLowerCase": "support tag"
}]
}]
}
I believe it has something to do with Clockify.Net/Models/Reports/SummaryGroup.cs
In there the property Id
is a string, and I believe in this case it shouldn't be.
As you can see in the JSON above, the _id fields in the groupOne array contain brackets around the IDs.
I am not sure whether it is always like that, hence logging this issue.
Apart from that, thanks for writing this nice wrapper!
Due to an API change it appears workspaces can no longer be deleted via the API, as such a workspace
generated by tests has to be manually deleted before tests can be re-run.
I suggest running all tests in a single workspace
and use uuid
to avoid name conflicts.
I'm unclear how to best approach the CreateWorkspace_ShouldCreateWorkspace
test as if a uuid
is used for name
, re-running tests will keep adding more workspaces which will then need to be manually deleted.
It seems that the new RestSharp 107.0.0 and later does not implement IRestRequest and other Interfaces, according to https://github.com/restsharp/RestSharp/releases/tag/107.0.0
When building with the new RestSharp package or if there is another RestSharp solution with Clockify.Net, an error occours
The fix seems to be just move from IRestRequest to RestRequest, but further analysis needs to be done.
Getting the project via nuget a lot of different packages will be installed in addition and results in time consuming uninstall and fixing things.
Remove CodeAnalysis and every other QA stuff (if possible) to have a smoother startup after nuget installation.
First of all, thanks for sharing this great project. ๐
Property Projects
on type DetailedReportRequest
is currently a string and can not be used. So I was not able to create a detailed report for a specific project.
I tried this type which works great:
using System.Collections.Generic;
namespace Clockify.Net.Models.Reports;
public class ProjectFilterType
{
public ContainsType Contains { get; set; }
public List<string> Ids { get; set; }
public StatusType Status { get; set; }
}
Also I changed:
using System;
using System.Collections.Generic;
namespace Clockify.Net.Models.Reports
{
public class DetailedReportRequest
{
....
public ProjectFilterType Projects { get; set; }
}
}
Should I create a PR for this?
Thanks,
Mariusz
-You you add the functionality to get all times from a user for a specific client?
-Also, could you add the variable clientid/client_name to the TimeEntryDtoImpl?
Unexpected character encountered while parsing value: {. Path 'timeentries[62].tags', line 1, position 34275.
Dropping that JSON into a debugger shows:
a.timeentries[62].tags
Array [ {โฆ} ]
โ
0: Object { name: "Billed", _id: "62c20bab791b1d5718ea06b0" }
โ
length: 1
โ
<prototype>: Array []
It looks like Clockify.Net expects these items to be strings, however the API appears to be returning a name/ID object, Clockify's documentation doesn't really detail what the summary endpoint expects.
First things first - thanks for implementing the Clockify Client, it's much appreciated! That being said, the following property of the UserSettingsDto
class public string LongRunning { get; set; }
is of type string
.
When the Clockify.me API returns its UserDto
object which contains the UserSettingsDto
object,
the content of the IRestResponse<List<UserDto>>
has UserSettingsDto.LongRunning
as the boolean value false
instead of a string value.
So when you try to deserialize it with JsonSerializer.Deserialize
, for example, you get an error.
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $[0].settings.longRunning | LineNumber: 0 | BytePositionInLine: 1069.\r\n ---> System.InvalidOperationException: Cannot get the value of a token type 'False' as a string.\r\n at System.Text.Json.Utf8JsonReader.GetString()\r\n..............
There's a temporary workaround to this issue, which is to implement a basic boolean JsonConverter that converts a string boolean value false to a string false.
Let me know if you have any questions!
-> Ability to find all the time entries in the project for a user. The project can be identified by its id. And also to add the ability to filter by different parameters.
-> Ability to find a project by it's id.
When calling Client.FindAllUsersOnWorkspaceAsync(workspaceId, page, pagesize) this error occurs:
Error converting value "PENDING_EMAIL_VERIFICATION" to type 'System.Nullable`1[Clockify.Net.Models.Users.UserStatus]'. Path '[18].status', line 1, position 33978.
The raw Content in the RestResponse.Content seams OK. Similar error with other user statuses different from "ACTIVE"
Using NuGet version 1.8.0
Maybe this should be a separate issue, but I've noticed ProjectRequest
and ProjectDtoImpl
are missing the Note
field
Originally posted by @GEPatSeeker in #11 (comment)
Originally posted by diogo1995santo July 8, 2021
Hello!
Are there currently any plans to add an option to update a Client name through this client?
-> Ability to add a new user to a workspace. The newly added user will receive an invitation via email to join the workspace.
-> Ability to find all the time entries for a project. The project can be identified by its id. And also to add the ability to filter by different parameters.
Currently the BaseUrl field is hardcoded and private, meaning its not possible to use this library for self hosted clockify:
https://github.com/Morasiu/Clockify.Net/blob/develop/Clockify.Net/ClockifyClient.cs#L13
The hourly rate is wrong in every function and the duration is also wrong.
Using for example FindAllHydratedTimeEntriesForUserAsync.
Originally posted by diogo1995santo July 8, 2021
Hello!
Are there currently any plans to add an option to update a Client name through this client?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.