How can I add a nested collection to an extension - gradle

new to Gradle. I have this simple plugin with an extension that allows me to write custom DSL:
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
apply plugin: NeighborhoodPlugin
class Street {
String name
String type
public Street(name) {
this.name = name
}
}
class Neighborhood {
final NamedDomainObjectContainer<Street> streets
def name
public Neighborhood(streets) {
this.streets = streets
}
def streets(Closure closure) {
streets.configure(closure)
}
}
// Plugin
class NeighborhoodPlugin implements Plugin<Project> {
void apply(Project project) {
// Create the NamedDomainObjectContainers
def streets = project.container(Street);
//https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtensionAware.html
def neighborhoodExt = project.extensions.create( 'neighborhood', Neighborhood, streets )
}
}
neighborhood {
name = 'My neighborhood'
streets {
street1 {
type = 'T'
}
street2 {
type = 'round'
}
}
}
task show {
doLast {
println "${neighborhood.name} has ${neighborhood.streets.toArray().length} streets"
}
}
The above seems to work. But I would like to expand on the DSL to add Houses to Streets. Something like this:
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
apply plugin: NeighborhoodPlugin
class House {
String name
String address
public House(name) {
this.name = name
}
}
class Street {
final NamedDomainObjectContainer<House> houses
String name
String type
public Street(name) {
this.name = name
}
}
class Neighborhood {
final NamedDomainObjectContainer<Street> streets
def name
public Neighborhood(streets) {
this.streets = streets
}
def streets(Closure closure) {
streets.configure(closure)
}
}
// Plugin
class NeighborhoodPlugin implements Plugin<Project> {
void apply(Project project) {
// Create the NamedDomainObjectContainers
def streets = project.container(Street);
//https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtensionAware.html
def neighborhoodExt = project.extensions.create( 'neighborhood', Neighborhood, streets )
}
}
neighborhood {
name = 'My neighborhood'
streets {
street1 {
type = 'T'
houses {
blueHouse {
address = '100 main'
}
}
}
street2 {
type = 'round'
}
}
}
task show {
doLast {
println "${neighborhood.name} has ${neighborhood.streets.toArray().length} streets"
}
}
I tried different combinations of things but I can never get to it to work. The error is always: No signature of method: build_ch0yxyi3isqke8j97jxnsaw72.neighborhood() is applicable for argument types.
Any help is really appreciated.

This works and I got it from: https://mrhaki.blogspot.com/2016/02/gradle-goodness-using-nested-domain.html:
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
apply plugin: NeighborhoodPlugin
class House {
String name
String address
public House(name) {
this.name = name
}
}
class Street {
NamedDomainObjectContainer<House> houses
String name
String type
public Street(name) {
this.name = name
}
def houses(Closure closure) {
houses.configure(closure)
}
}
class Neighborhood {
final NamedDomainObjectContainer<Street> streets
def name
public Neighborhood(streets) {
this.streets = streets
}
def streets(Closure closure) {
streets.configure(closure)
}
}
// Plugin
class NeighborhoodPlugin implements Plugin<Project> {
void apply(Project project) {
// Create the NamedDomainObjectContainers
def streets = project.container(Street);
streets.all {
houses = project.container(House)
}
//https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtensionAware.html
def neighborhoodExt = project.extensions.create( 'neighborhood', Neighborhood, streets )
}
}
neighborhood {
name = 'My neighborhood'
streets {
main {
type = 'Cul de-sac'
houses {
blueHouse {
address = '100 main'
}
pinkHouse {
address = '101 main'
}
greenHouse {
address = '103 main'
}
}
}
round {
type = 'Round'
houses {
yellowHouse {
address = '100 round'
}
greenHouse {
address = '101 round'
}
}
}
}
}
task show {
doLast {
println "${neighborhood.name} has ${neighborhood.streets.toArray().length} streets"
neighborhood.streets.all {
println "--> name: ${name}"
houses.all {
println "--> --> name: ${name} address: ${address}"
}
}
}
}

Related

SonarQube ignoring AbstractValidator test classes

SonarQube ignores tests for AbstractValidators (FluentValidation.AspNetCore nuget package). In the coverage section, all RuleFor lines are marked as not covered.
What do I need to do, for the tests to be included in the coverage in SonarQube?
ReSharper shows the validator as being fully covered by tests.
The validator:
public class UserValidator : AbstractValidator<User>
{
public UserValidator()
{
RuleFor(a => a.Name).NotEmpty();
RuleFor(a => a.FirstName).NotEmpty();
}
}
Test class:
public class UserValidatorTests
{
[Test, TestCaseSource(nameof(User_InvalidData))]
public async Task ValidationShouldFail(UserAndErrors testData)
{
var result = await new UserValidator().TestValidateAsync(testData.User!);
Assert.IsFalse(result.IsValid);
Assert.AreEqual(result.Errors.Count, testData.ErrorsCount);
}
[Test]
public async Task ValidationShouldPass()
{
var request = new User
{
FirstName = "John",
Name= "Doe"
};
var result = await new UserValidator().TestValidateAsync(request);
Assert.IsTrue(result.IsValid);
result.ShouldNotHaveAnyValidationErrors();
}
private static IEnumerable<TestCaseData> User_InvalidData()
{
yield return new TestCaseData(new User
{
User = new User(),
ErrorsCount = 2
});
yield return new TestCaseData(new User
{
User = new User
{
Name = "Doe"
},
ErrorsCount = 1
});
yield return new TestCaseData(new User
{
User = new User
{
FirstName = "John"
},
ErrorsCount = 1
});
}
public class UserAndErrors
{
public User? User { get; set; }
public int ErrorsCount { get; set; } = 0;
}
}
User class:
public class User
{
public string Name { get; set; } = string.Empty;
public string FirstName { get; set; } = string.Empty;
}
The issue was the fact that the test project did not reference the coverlet.msbuild nuget package. Without it, SonarQube could not run the tests correctly and could not update the code coverage.

How to generate OpenAPI via Gradle for Amazon Selling Partner API models?

I'm new to Gradle (using 7.3.2) and currently trying to integrate org.openapi.generator's openApiGenerate task for all json OpenAPI template files of Amazon's selling partner API models from https://github.com/amzn/selling-partner-api-models.
plugins {
id 'org.ajoberstar.grgit' version '4.1.1'
id 'org.openapi.generator' version '5.3.0'
}
import org.ajoberstar.grgit.Grgit
project.ext.repoDirectory = "$buildDir/selling-partner-api-models"
project.ext.basePackage = "com.amazon.sellingpartner"
tasks.register('deleteRepo', Delete) {
delete project.ext.repoDirectory
}
class CloneSpapi extends DefaultTask {
#Input
String url = 'https://github.com/amzn/selling-partner-api-models.git'
#TaskAction
def clone() {
println 'Cloning Amazon Selling Partner OpenAPI from github ...'
def grgit = Grgit.clone(dir: project.ext.repoDirectory, uri: url)
grgit.close()
println 'done'
}
}
tasks.register('cloneSpapi', CloneSpapi) {
description 'Clones Amazon Selling Partner OpenAPI from github'
dependsOn tasks.named('deleteRepo')
}
interface GenerateParameters extends WorkParameters {
RegularFileProperty getJsonFile()
DirectoryProperty getOutputDir()
}
abstract class GenerateApi implements WorkAction<GenerateParameters> {
#Override
void execute() {
def file = parameters.jsonFile.get().getAsFile()
def modelName = file.getName().replace('.json', '')
println modelName + ": " + file
}
}
abstract class GenerateApis extends DefaultTask {
private final WorkerExecutor workerExecutor
#Input
abstract String directory = "$project.ext.repoDirectory/models"
#Inject
GenerateApis(WorkerExecutor workerExecutor) {
this.workerExecutor = workerExecutor
}
#TaskAction
void generateFiles() {
ConfigurableFileTree tree = project.fileTree(dir: directory)
tree.include '**/*.json'
Set<File> modelFiles = tree.getFiles().sort()
WorkQueue workQueue = workerExecutor.noIsolation()
modelFiles.each { File file ->
workQueue.submit(GenerateApi.class) { GenerateParameters parameters ->
parameters.jsonFile = file
}
}
}
}
tasks.register('generateApis', GenerateApis) {
}
openApiGenerate {
generatorName = "java"
inputSpec = // file
outputDir = "$buildDir/generated".toString()
invokerPackage = "$project.ext.basePackage"
apiPackage = "$project.ext.basePackage" + ".api.modelName" // modelName from
modelPackage = "$project.ext.basePackage" + ".model.modelName" // modelName here
configOptions = [
dateLibrary: "java8"
]
}
To simplify things, I have added a simple 'cloneSpapi' task to clone the repository.
gradle -q cloneSpapi
How do I call the openApiGenerate task for each template file?
I have now used the swagger.io library directly and was able to call the code generator directly.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("io.swagger:swagger-codegen:2.4.24")
}
}
plugins {
id 'org.ajoberstar.grgit' version '4.1.1'
}
import io.swagger.codegen.DefaultGenerator
import io.swagger.codegen.config.CodegenConfigurator
import org.ajoberstar.grgit.Grgit
project.ext.repoDirectory = "$buildDir/selling-partner-api-models"
project.ext.basePackage = "com.amazon.sellingpartner"
project.ext.outputDir = new File(project.buildDir, '/generated')
tasks.register('deleteRepo', Delete) {
delete project.ext.repoDirectory
}
class CloneSpapi extends DefaultTask {
#Input
String url = 'https://github.com/amzn/selling-partner-api-models.git'
#TaskAction
def clone() {
println 'Cloning Amazon Selling Partner OpenAPI from github ...'
def grgit = Grgit.clone(dir: project.ext.repoDirectory, uri: url)
grgit.close()
println 'done'
}
}
tasks.register('cloneSpapi', CloneSpapi) {
description 'Clones Amazon Selling Partner OpenAPI from github'
dependsOn tasks.named('deleteRepo')
}
interface GenerateParameters extends WorkParameters {
RegularFileProperty getJsonFile()
DirectoryProperty getTemplateDir()
DirectoryProperty getOutputDir()
Property<String> getBasePackage()
}
abstract class GenerateApi implements WorkAction<GenerateParameters> {
#Override
void execute() {
def file = parameters.jsonFile.get().getAsFile()
def modelName = file.getName().replace('.json', '')
println "Generating OpenAPI for $modelName"
def basePackage = parameters.basePackage.get()
def config = new CodegenConfigurator()
config.setInputSpec(file.toString()) // The swagger API file
config.setLang("java")
config.setTemplateDir(parameters.templateDir.get().toString())
config.setOutputDir(parameters.outputDir.get().toString()) // The output directory, user-service-contract/build/user-service-server/
config.setInvokerPackage(basePackage)
config.setApiPackage(basePackage + ".api." + modelName) // Package to be used for the API interfaces
config.setModelPackage(basePackage + ".model." + modelName) // Package to be used for the API models
config.setAdditionalProperties([
'dateLibrary' : 'java8', // Date library to use
'useTags' : 'true' // Use tags for the naming
])
def generator = new DefaultGenerator();
generator.opts(config.toClientOptInput());
generator.generate()
}
}
abstract class GenerateApis extends DefaultTask {
private final WorkerExecutor workerExecutor
#Input
abstract String directory = "$project.ext.repoDirectory/models"
#Inject
GenerateApis(WorkerExecutor workerExecutor) {
this.workerExecutor = workerExecutor
}
#TaskAction
void generate() {
ConfigurableFileTree tree = project.fileTree(dir: directory)
tree.include '**/*.json'
Set<File> modelFiles = tree.getFiles().sort()
WorkQueue workQueue = workerExecutor.noIsolation()
modelFiles.each { File file ->
workQueue.submit(GenerateApi.class) { GenerateParameters parameters ->
parameters.jsonFile = file
parameters.templateDir = new File(project.ext.repoDirectory, 'clients/sellingpartner-api-aa-java/resources/swagger-codegen/templates')
parameters.outputDir = project.ext.outputDir
parameters.basePackage = project.ext.basePackage
}
}
}
}
tasks.register('deleteGenerated', Delete) {
delete project.ext.outputDir
}
tasks.register('generateApis', GenerateApis) {
dependsOn tasks.named('deleteGenerated'), tasks.named('cloneSpapi')
}

I have a problem with the code in ViewModel + Kotlin Coroutines + LiveData

I have a ViewModel
#HiltViewModel
class LoginViewModel #Inject constructor(
private val apiRepository: ApiRepository
) : ViewModel() {
private val account = MutableLiveData<String>("123")
private val password = MutableLiveData<String>("123")
val message: MutableLiveData<String> = MutableLiveData()
var loginResult: LiveData<Resource<UserInfo>> = MutableLiveData()
fun signIn() {
if (TextUtils.isEmpty(account.value)) {
message.postValue("Please enter your account")
return
}
if (TextUtils.isEmpty(password.value)) {
message.postValue("please enter your password")
return
}
// In this code, it doesn’t work. I think it’s because I didn’t observe it.
// Is there any better way to write it here?
loginResult = apiRepository.signIn(account.value!!, password.value!!)
}
fun inputAccount(accountValue: String) {
account.value = accountValue
}
fun inputPassword(passwordValue: String) {
password.value = passwordValue
}
}
This is my interface
#AndroidEntryPoint
class LoginActivity : BaseActivity<ActivityLoginBinding>() {
private val viewModel: LoginViewModel by viewModels()
......
override fun initEvent() {
binding.account.editText!!.addTextChangedListener { viewModel.inputAccount(it.toString()) }
binding.password.editText!!.addTextChangedListener { viewModel.inputPassword(it.toString()) }
binding.signIn.setOnClickListener {
viewModel.signIn()
}
}
override fun setupObservers() {
viewModel.message.observe(this) {
Snackbar.make(binding.root, it, Snackbar.LENGTH_SHORT).show()
}
/**
* There will be no callback here, I know it’s because I’m observing
* `var loginResult: LiveData<Resource<UserInfo>> = MutableLiveData()`
* instead of `apiRepository.signIn(account.value!!, password.value!!)`
* because it was reassigned
*/
viewModel.loginResult.observe(this) {
Log.d("TAG", "setupObservers: $it")
}
}
}
So I adjusted the code a bit
LoginViewModel.signIn
fun signIn(): LiveData<Resource<UserInfo>>? {
if (TextUtils.isEmpty(account.value)) {
message.postValue("Please enter your account")
return null
}
if (TextUtils.isEmpty(password.value)) {
message.postValue("please enter your password")
return null
}
return apiRepository.signIn(account.value!!, password.value!!)
}
LoginActivity.initEvent
override fun initEvent() {
binding.signIn.setOnClickListener {
viewModel.signIn()?.observe(this) {
Log.d("TAG", "setupObservers: $it")
}
}
}
I have checked the official documents of LiveData, and all call livedata{} during initialization. There has been no re-assignment, but if you log in, you cannot directly start the application and request the network.
coroutines doucument
Although I finally achieved my results, I think this is not the best practice, so I want to ask for help!
Supplementary code
ApiRepository
class ApiRepository #Inject constructor(
private val apiService: ApiService
) : BaseRemoteDataSource() {
fun signIn(account: String, password: String) =
getResult { apiService.signIn(account, password) }
}
BaseRemoteDataSource
abstract class BaseRemoteDataSource {
protected fun <T> getResult(call: suspend () -> Response<T>): LiveData<Resource<T>> =
liveData(Dispatchers.IO) {
try {
val response = call.invoke()
if (response.isSuccessful) {
val body = response.body()
if (body != null) emit(Resource.success(body))
} else {
emit(Resource.error<T>(" ${response.code()} ${response.message()}"))
}
} catch (e: Exception) {
emit(Resource.error<T>(e.message ?: e.toString()))
}
}
}
Or i write like this
fun signIn() {
if (TextUtils.isEmpty(account.value)) {
message.postValue("Please enter your account")
return
}
if (TextUtils.isEmpty(password.value)) {
message.postValue("please enter your password")
return
}
viewModelScope.launch {
repository.signIn(account.value, password.value).onEach {
loginResult.value = it
}
}
}
But I think this is not perfect

Gradle: How to init SourceTask's property ‘source’ with extension property?

My plugin registers an extension and some custom task that inherited from org.gradle.api.tasks.SourceTask.
class MyPlugin implements Plugin<Project> {
private final Instantiator instantiator
private final FileResolver fileResolver
#Inject
MyPlugin (Instantiator instantiator, FileResolver fileResolver) {
this.instantiator = instantiator
this.fileResolver = fileResolver
}
void apply(Project project) {
MyPluginExtension extension = project.extensions.create("myPlugin", MyPluginExtension, project, instantiator, fileResolver)
project.tasks.create('doSomething', MyCustomTask) {}
}
}
class MyPluginExtension {
final MySourceSetContainer source
MyPluginExtension(Project project, Instantiator instantiator, FileResolver fileResolver) {
source = instantiator.newInstance(ImplMySourceSetContainer, project, instantiator, fileResolver)
}
void source(Closure closure) {
ConfigureUtil.configure(closure, source)
}
}
class MyCustomTask extends SourceTask {
#TaskAction
void act() {
// something
}
}
And now, if I configure build script:
myPlugin {
source{
main {
something {
srcDirs "src/main/resources"
}
}
}
}
doSomething {
source = myPlugin.source.main.something.asFileTree
}
- All works fine. But I want to initialize task property source by value from MyPluginExtension.
source = extension.source.findAll().inject(project.files().asFileTree, { result, item -> result + item.html.asFileTree })
I can't extract extension property at the execution phase as it described in the userguide (https://docs.gradle.org/4.2.1/userguide/custom_plugins.html#sec:mapping_extension_properties_to_task_properties), because getter for source that declared in superclass org.gradle.api.tasks.SourceTask marked with annotation #org.gradle.api.tasks.SkipWhenEmpty and task will be skipped.
How can I initialize task's property with value from extension before execution phase?
Thx.
I'm not sure that I fully understand what you are doing but you could likely use a closure to delay evaluation. See Project.files(Object...)
Eg:
doSomething {
def myClosure = {
extension.source.findAll().inject(project.files().asFileTree, { result, item -> result + item.html.asFileTree })
}
source = files(myClosure)
}
Resolved by wrapping source init in closure:
class MyPlugin implements Plugin<Project> {
// ...
void apply(Project project) {
MyPluginExtension extension = project.extensions.create("myPlugin", MyPluginExtension, project, instantiator, fileResolver)
project.tasks.create('doSomething', MyCustomTask) { task ->
task.source = {
extension.source.findAll().inject(new HashSet<File>(), { result, item -> result + item.html.srcDirs })
}
}
}
}

How to get associated name of linked resources in HAL

I am creating an API for project tasks. It has a TasksController as listed below. I am generating hypermedia using WebApi.Hal and the service supports hal+json and hal+xml media types also.
Following is the response I currently have for the GET request http://localhost:51910/api/tasks/1. In the response there is a list of links for priorities – but they don’t have associated name in the response (to show in the UI – like Low, Medium, High, etc.).
What is the best HAL approach for getting name of the priorities also, using WebApi.HAL?
Note: The list of priorities can be enhanced in the future.
Priority
public class Priority
{
public int PriorityID { get; set; }
public string PriorityName { get; set; }
public string Revision { get; set; }
public DateTime ApprovalDate { get; set; }
}
Controller
public class TasksController : ApiController
{
// GET api/values/5
[HttpGet]
public TaskRepresentation Get(int id)
{
Task selectedTask = TasksHelper.GetTask(id);
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
//PUT For Setting Priority
[HttpPut]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public TaskRepresentation PutSetPriority(int taskID, int priorityID)
{
Task selectedTask = TasksHelper.GetTask(taskID);
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
//Update Task
if (selectedPriority != null)
{
selectedTask.CurrentPriority = selectedPriority.PriorityName;
}
else
{
throw new Exception("Not available");
}
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
[HttpGet]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public Priority Get(int taskID, int priorityID)
{
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
return selectedPriority;
}
}
HAL Generation Related Classes
public static class LinkTemplates
{
public static class TaskLinks
{
public static Link TaskEntry { get { return new Link("self", "~/api/tasks/{taskID}"); } }
public static Link PriorityLink { get { return new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}"); } }
}
}
public class TaskRepresentation : Representation
{
Task theTask;
public int TaskID{get{return theTask.TaskID;}}
public string TaskName{get{return theTask.Name;}}
public string CurrentPriority{get{return theTask.CurrentPriority;}}
public string Category{get{return theTask.Category;}}
public TaskRepresentation(Task t)
{
theTask = t;
}
public override string Rel
{
get { return LinkTemplates.TaskLinks.TaskEntry.Rel; }
set { }
}
public override string Href
{
get { return LinkTemplates.TaskLinks.TaskEntry.CreateLink(new { taskID = theTask.TaskID }).Href; }
set { }
}
protected override void CreateHypermedia()
{
foreach (Priority p in theTask.PossiblePriorities)
{
Links.Add(LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID }));
}
}
}
HAL Specification mentions title - this will meet the requirement.
Following is the updated response.
{
"TaskID": 1,
"TaskName": "Task1",
"CurrentPriority": "Medium",
"Category": "IT",
"_links": {
"self": {
"href": "/api/tasks/1"
},
"priorities": [
{
"href": "/api/tasks/1/priorities/101",
"title": "Low"
},
{
"href": "/api/tasks/1/priorities/103",
"title": "High"
},
{
"href": "/api/tasks/1/priorities/104",
"title": "Critical"
}
]
}
}
WebAPI.HAL changes
protected override void CreateHypermedia()
{
foreach (Priority p in theTask.PossiblePriorities)
{
Link lnk = LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID });
lnk.Title = p.PriorityName;
Links.Add(lnk);
}
}
Code
public static class LinkTemplates
{
public static class TaskLinks
{
public static Link TaskEntry { get { return new Link("self", "~/api/tasks/{taskID}"); } }
//public static Link PriorityLink { get { return new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}"); } }
public static Link PriorityLink
{
get
{
Link l = new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}");
return l;
}
}
}
}
public class TasksController : ApiController
{
// GET api/values/5
[HttpGet]
public TaskRepresentation Get(int id)
{
Task selectedTask = TasksHelper.GetTask(id);
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
//PUT For Setting Priority
[HttpPut]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public TaskRepresentation PutSetPriority(int taskID, int priorityID)
{
Task selectedTask = TasksHelper.GetTask(taskID);
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
//Update Task
if (selectedPriority != null)
{
selectedTask.CurrentPriority = selectedPriority.PriorityName;
}
else
{
throw new Exception("Not available");
}
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
[HttpGet]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public Priority Get(int taskID, int priorityID)
{
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
return selectedPriority;
}
}
public class TaskRepresentation : Representation
{
Task theTask;
public int TaskID{get{return theTask.TaskID;}}
public string TaskName{get{return theTask.Name;}}
public string CurrentPriority{get{return theTask.CurrentPriority;}}
public string Category{get{return theTask.Category;}}
public TaskRepresentation(Task t)
{
theTask = t;
}
public override string Rel
{
get { return LinkTemplates.TaskLinks.TaskEntry.Rel; }
set { }
}
public override string Href
{
get { return LinkTemplates.TaskLinks.TaskEntry.CreateLink(new { taskID = theTask.TaskID }).Href; }
set { }
}
protected override void CreateHypermedia()
{
foreach (Priority p in theTask.PossiblePriorities)
{
Link lnk = LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID });
lnk.Title = p.PriorityName;
Links.Add(lnk);
}
}
}
public class Task
{
public string Name { get; set; }
public int TaskID { get; set; }
public string Category { get; set; }
public string CurrentPriority { get; set; }
public List<Priority> PossiblePriorities { get; set; }
}
public class Priority
{
public int PriorityID { get; set; }
public string PriorityName { get; set; }
public string Revision { get; set; }
public DateTime ApprovalDate { get; set; }
}
public static class TasksPrioritiesHelper
{
public static List<Priority> GetAllPriorities()
{
List<Priority> possiblePriorities = new List<Priority>();
Priority pLow = new Priority { PriorityID = 101, PriorityName = "Low" };
Priority pMedium = new Priority { PriorityID = 102, PriorityName = "Medium" };
Priority pHigh = new Priority { PriorityID = 103, PriorityName = "High" };
Priority pCritical = new Priority { PriorityID = 104, PriorityName = "Critical" };
possiblePriorities.Add(pLow);
possiblePriorities.Add(pMedium);
possiblePriorities.Add(pHigh);
possiblePriorities.Add(pCritical);
return possiblePriorities;
}
public static List<Priority> GetAdministrativePriorities()
{
List<Priority> possiblePriorities = new List<Priority>();
Priority pLow = new Priority { PriorityID = 101, PriorityName = "Low" };
Priority pHigh = new Priority { PriorityID = 103, PriorityName = "High" };
possiblePriorities.Add(pLow);
possiblePriorities.Add(pHigh);
return possiblePriorities;
}
public static List<Priority> GetPossiblePrioritiesForTask(Task t)
{
List<Priority> possibleTaskPriorities = new List<Priority>();
if (String.Equals(t.Category, "IT"))
{
possibleTaskPriorities = GetAllPriorities();
}
else
{
possibleTaskPriorities = GetAdministrativePriorities();
}
Priority currentTaskPriority = null;
foreach(Priority p in possibleTaskPriorities )
{
if(String.Equals(t.CurrentPriority,p.PriorityName ))
{
currentTaskPriority=p;
}
}
if(currentTaskPriority!=null)
{
possibleTaskPriorities.Remove(currentTaskPriority);
}
return possibleTaskPriorities;
}
}
public static class TasksHelper
{
public static Task GetTask(int id)
{
Task selectedTask = null;
List<Task> tasks = GetAllTasks();
foreach (Task t in tasks)
{
if(t.TaskID==id)
{
selectedTask = t;
}
}
return selectedTask;
}
public static List<Task> GetAllTasks()
{
List<Task> tasks;
tasks = new List<Task>();
Task t1 = new Task{Category = "IT",CurrentPriority = "Medium",Name = "Task1",TaskID = 1};
t1.PossiblePriorities = TasksPrioritiesHelper.GetPossiblePrioritiesForTask(t1);
tasks.Add(t1);
return tasks;
}
}

Resources