Linked raceData from new xml formats to current program. Current app now shows the starting list and course boundary. #story[782]
This commit is contained in:
@@ -9,6 +9,7 @@ import javafx.fxml.FXML;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import org.xml.sax.SAXException;
|
||||
import seng302.Mock.StreamedRace;
|
||||
import seng302.Model.*;
|
||||
import seng302.RaceDataSource;
|
||||
import seng302.RaceXMLReader;
|
||||
@@ -116,14 +117,14 @@ public class RaceController extends Controller {
|
||||
* @param scaleFactor scale value of race
|
||||
*/
|
||||
public void startRace(int scaleFactor, RaceDataSource raceData) {
|
||||
ConstantVelocityRace newRace = new ConstantVelocityRace(raceData, this, scaleFactor);
|
||||
newRace.initialiseBoats();
|
||||
StreamedRace newRace = new StreamedRace(raceData, this, scaleFactor);
|
||||
//newRace.initialiseBoats();
|
||||
|
||||
raceMap = new ResizableRaceCanvas(raceData);
|
||||
raceMap.setMouseTransparent(true);
|
||||
raceMap.widthProperty().bind(canvasBase.widthProperty());
|
||||
raceMap.heightProperty().bind(canvasBase.heightProperty());
|
||||
raceMap.setBoats(newRace.getStartingBoats());
|
||||
//raceMap.setBoats(newRace.getStartingBoats());
|
||||
raceMap.setRaceBoundaries(raceData.getBoundary());
|
||||
raceMap.drawRaceMap();
|
||||
raceMap.setVisible(true);
|
||||
|
||||
@@ -13,6 +13,7 @@ import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import org.xml.sax.SAXException;
|
||||
import seng302.Mock.*;
|
||||
import seng302.Model.BoatInRace;
|
||||
import seng302.Model.RaceClock;
|
||||
import seng302.RaceDataSource;
|
||||
@@ -21,6 +22,7 @@ import seng302.RaceXMLReader;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@@ -81,13 +83,20 @@ public class StartController extends Controller {
|
||||
public void initialize(URL location, ResourceBundle resources){
|
||||
raceData = null;
|
||||
try {
|
||||
raceData = new RaceXMLReader("raceXML/bermuda_AC35.xml");
|
||||
StreamedCourse streamedCourse = new StreamedCourse(new BoatXMLReader("mockXML/boatXML/boatTest.xml"));
|
||||
streamedCourse.setStreamedCourseXMLReader(new StreamedCourseXMLReader("mockXML/raceXML/raceTest.xml"));
|
||||
streamedCourse.setRegattaXMLReader(new RegattaXMLReader("mockXML/regattaXML/regattaTest.xml"));
|
||||
raceData = streamedCourse;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SAXException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
} catch (StreamedCourseXMLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
initialiseTables();
|
||||
setRaceClock();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package seng302.Mock;
|
||||
|
||||
import seng302.GPSCoordinate;
|
||||
|
||||
/**
|
||||
* Created by jjg64 on 19/04/17.
|
||||
*/
|
||||
@@ -96,4 +98,8 @@ public class Regatta {
|
||||
public void setMagneticVariation(float magneticVariation) {
|
||||
this.magneticVariation = magneticVariation;
|
||||
}
|
||||
|
||||
public GPSCoordinate getGPSCoordinate() {
|
||||
return new GPSCoordinate(centralLatitude, centralLongitude);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,26 +3,55 @@ package seng302.Mock;
|
||||
import seng302.GPSCoordinate;
|
||||
import seng302.Model.BoatInRace;
|
||||
import seng302.Model.Leg;
|
||||
import seng302.Model.RaceClock;
|
||||
import seng302.RaceDataSource;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by jjg64 on 21/04/17.
|
||||
*/
|
||||
public class StreamedCourse implements RaceDataSource {
|
||||
StreamedCourseXMLReader streamedCourseXMLReader;
|
||||
StreamedCourseXMLReader streamedCourseXMLReader = null;
|
||||
BoatXMLReader boatXMLReader = null;
|
||||
RegattaXMLReader regattaXMLReader = null;
|
||||
List<GPSCoordinate> boundary = new ArrayList<>();
|
||||
|
||||
public StreamedCourse(StreamedCourseXMLReader streamedCourseXMLReader) {
|
||||
this.streamedCourseXMLReader = streamedCourseXMLReader;
|
||||
}
|
||||
|
||||
public StreamedCourse(BoatXMLReader boatXMLReader) {
|
||||
this.boatXMLReader = boatXMLReader;
|
||||
}
|
||||
|
||||
public void setBoatXMLReader(BoatXMLReader boatXMLReader) {
|
||||
this.boatXMLReader = boatXMLReader;
|
||||
if (streamedCourseXMLReader != null) {
|
||||
boatXMLReader.setParticipants(streamedCourseXMLReader.getParticipants());
|
||||
boatXMLReader.read();
|
||||
}
|
||||
}
|
||||
|
||||
public void setStreamedCourseXMLReader(StreamedCourseXMLReader streamedCourseXMLReader) {
|
||||
this.streamedCourseXMLReader = streamedCourseXMLReader;
|
||||
if (streamedCourseXMLReader != null) {
|
||||
boatXMLReader.setParticipants(streamedCourseXMLReader.getParticipants());
|
||||
boatXMLReader.read();
|
||||
}
|
||||
}
|
||||
|
||||
public void setRegattaXMLReader(RegattaXMLReader regattaXMLReader) {
|
||||
this.regattaXMLReader = regattaXMLReader;
|
||||
}
|
||||
|
||||
public RegattaXMLReader getRegattaXMLReader() {
|
||||
return regattaXMLReader;
|
||||
}
|
||||
|
||||
public List<BoatInRace> getBoats() {
|
||||
return null;
|
||||
return new ArrayList<>(boatXMLReader.getStreamedBoatMap().values());
|
||||
}
|
||||
|
||||
public List<Leg> getLegs() {
|
||||
@@ -34,7 +63,7 @@ public class StreamedCourse implements RaceDataSource {
|
||||
}
|
||||
|
||||
public ZonedDateTime getZonedDateTime() {
|
||||
return null;
|
||||
return RaceClock.getCurrentZonedDateTime(regattaXMLReader.getRegatta().getGPSCoordinate());
|
||||
}
|
||||
|
||||
public GPSCoordinate getMapTopLeft() {
|
||||
@@ -44,7 +73,4 @@ public class StreamedCourse implements RaceDataSource {
|
||||
public GPSCoordinate getMapBottomRight() {
|
||||
return streamedCourseXMLReader.getMapBottomRight();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ public class StreamedCourseXMLReader extends XMLReader {
|
||||
private GPSCoordinate mapTopLeft, mapBottomRight;
|
||||
private List<GPSCoordinate> boundary = new ArrayList<>();
|
||||
private Map<Integer,Element> marks = new HashMap<>();
|
||||
private Map<Integer, StreamedBoat> participants = new HashMap<>();
|
||||
private List<Leg> legs = new ArrayList<>();
|
||||
Date creationTimeDate;
|
||||
Date raceStartTime;
|
||||
@@ -77,8 +78,17 @@ public class StreamedCourseXMLReader extends XMLReader {
|
||||
}
|
||||
|
||||
private void readParticipants() {
|
||||
//TODO Modify BoatInRace to take in a sourceID
|
||||
//TODO Produce list of BoatInRace
|
||||
Element nParticipants = (Element) doc.getElementsByTagName("Participants").item(0);
|
||||
for (int i = 0; i < nParticipants.getChildNodes().getLength(); i++) {
|
||||
int sourceID;
|
||||
Node yacht = nParticipants.getChildNodes().item(i);
|
||||
if (yacht.getNodeName().equals("Yacht")) {
|
||||
if (exists(yacht, "SourceID")) {
|
||||
sourceID = Integer.parseInt(yacht.getAttributes().getNamedItem("SourceID").getTextContent());
|
||||
participants.put(sourceID, new StreamedBoat(sourceID));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readCourse() throws StreamedCourseXMLException {
|
||||
@@ -222,4 +232,8 @@ public class StreamedCourseXMLReader extends XMLReader {
|
||||
public boolean isPostpone() {
|
||||
return postpone;
|
||||
}
|
||||
|
||||
public Map<Integer, StreamedBoat> getParticipants() {
|
||||
return participants;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +318,8 @@ public class ResizableRaceCanvas extends Canvas {
|
||||
* Draws boats while race in progress, when leg heading is set.
|
||||
*/
|
||||
public void updateBoats() {
|
||||
// TODO Remove null when boats are ready
|
||||
boats = null;
|
||||
if (boats != null) {
|
||||
for (BoatInRace boat : boats) {
|
||||
boolean finished = boat.getCurrentLeg().getName().equals("Finish") || boat.getCurrentLeg().getName().equals("DNF");
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<BoatConfig>
|
||||
|
||||
<Modified>2012-05-17T07:49:40+0200</Modified>
|
||||
|
||||
<Version>12</Version>
|
||||
|
||||
<Settings>
|
||||
|
||||
<RaceBoatType Type="AC45" />
|
||||
|
||||
<BoatDimension BoatLength="14.019" HullLength="13.449" />
|
||||
|
||||
<ZoneSize MarkZoneSize="40.347" CourseZoneSize="40.347" />
|
||||
|
||||
<ZoneLimits Limit1="200" Limit2="100" Limit3="40.347" Limit4="0" Limit5="-100" />
|
||||
|
||||
</Settings>
|
||||
|
||||
<BoatShapes>
|
||||
|
||||
<BoatShape ShapeID="0">
|
||||
|
||||
<Vertices>
|
||||
|
||||
<Vtx Seq="1" Y="0" X="-2.659" />
|
||||
|
||||
<Vtx Seq="2" Y="18.359" X="-2.659" />
|
||||
|
||||
<Vtx Seq="3" Y="18.359" X="2.659" />
|
||||
|
||||
<Vtx Seq="4" Y="0" X="2.659" />
|
||||
|
||||
</Vertices>
|
||||
|
||||
</BoatShape>
|
||||
|
||||
<BoatShape ShapeID="1">
|
||||
|
||||
<Vertices>
|
||||
|
||||
<Vtx Seq="1" Y="0" X="-1.278" />
|
||||
|
||||
<Vtx Seq="2" Y="8.876" X="-1.278" />
|
||||
|
||||
<Vtx Seq="3" Y="8.876" X="1.278" />
|
||||
|
||||
<Vtx Seq="4" Y="0" X="1.278" />
|
||||
|
||||
</Vertices>
|
||||
|
||||
</BoatShape>
|
||||
|
||||
<BoatShape ShapeID="2">
|
||||
|
||||
<Vertices>
|
||||
|
||||
<Vtx Seq="1" Y="0" X="-1.1" />
|
||||
|
||||
<Vtx Seq="2" Y="8.3" X="-1.1" />
|
||||
|
||||
<Vtx Seq="3" Y="8.3" X="1.1" />
|
||||
|
||||
<Vtx Seq="4" Y="0" X="1.1" />
|
||||
|
||||
</Vertices>
|
||||
|
||||
</BoatShape>
|
||||
|
||||
<BoatShape ShapeID="3">
|
||||
|
||||
<Vertices>
|
||||
|
||||
<Vtx Seq="1" Y="0" X="-0.75" />
|
||||
|
||||
<Vtx Seq="2" Y="3" X="-0.75" />
|
||||
|
||||
<Vtx Seq="3" Y="3" X="0.75" />
|
||||
|
||||
<Vtx Seq="4" Y="0" X="0.75" />
|
||||
|
||||
</Vertices>
|
||||
|
||||
</BoatShape>
|
||||
|
||||
<BoatShape ShapeID="4">
|
||||
|
||||
<Vertices>
|
||||
|
||||
<Vtx Seq="1" Y="0" X="-3.46" />
|
||||
|
||||
<Vtx Seq="2" Y="13.449" X="-3.46" />
|
||||
|
||||
<Vtx Seq="3" Y="14.019" X="0" />
|
||||
|
||||
<Vtx Seq="4" Y="13.449" X="3.46" />
|
||||
|
||||
<Vtx Seq="5" Y="0" X="3.46" />
|
||||
|
||||
</Vertices>
|
||||
|
||||
<Catamaran>
|
||||
|
||||
<Vtx Seq="1" Y="1.769" X="-2.752" />
|
||||
|
||||
<Vtx Seq="2" Y="0" X="-2.813" />
|
||||
|
||||
<Vtx Seq="3" Y="0" X="-3.34" />
|
||||
|
||||
<Vtx Seq="4" Y="5.351" X="-3.46" />
|
||||
|
||||
<Vtx Seq="5" Y="10.544" X="-3.387" />
|
||||
|
||||
<Vtx Seq="6" Y="13.449" X="-3.075" />
|
||||
|
||||
<Vtx Seq="7" Y="10.851" X="-2.793" />
|
||||
|
||||
<Vtx Seq="8" Y="6.669" X="-2.699" />
|
||||
|
||||
<Vtx Seq="9" Y="6.669" X="2.699" />
|
||||
|
||||
<Vtx Seq="10" Y="10.851" X="2.793" />
|
||||
|
||||
<Vtx Seq="11" Y="13.449" X="3.075" />
|
||||
|
||||
<Vtx Seq="12" Y="10.544" X="3.387" />
|
||||
|
||||
<Vtx Seq="13" Y="5.351" X="3.46" />
|
||||
|
||||
<Vtx Seq="14" Y="0" X="3.34" />
|
||||
|
||||
<Vtx Seq="15" Y="0" X="2.813" />
|
||||
|
||||
<Vtx Seq="16" Y="1.769" X="2.752" />
|
||||
|
||||
</Catamaran>
|
||||
|
||||
<Bowsprit>
|
||||
|
||||
<Vtx Seq="1" Y="6.669" X="-0.2" />
|
||||
|
||||
<Vtx Seq="2" Y="11.377" X="-0.2" />
|
||||
|
||||
<Vtx Seq="3" Y="14.019" X="0" />
|
||||
|
||||
<Vtx Seq="4" Y="11.377" X="0.2" />
|
||||
|
||||
<Vtx Seq="5" Y="6.669" X="0.2" />
|
||||
|
||||
</Bowsprit>
|
||||
|
||||
<Trampoline>
|
||||
|
||||
<Vtx Seq="1" Y="2" X="-2.699" />
|
||||
|
||||
<Vtx Seq="2" Y="6.438" X="-2.699" />
|
||||
|
||||
<Vtx Seq="3" Y="6.438" X="2.699" />
|
||||
|
||||
<Vtx Seq="4" Y="2" X="2.699" />
|
||||
|
||||
</Trampoline>
|
||||
|
||||
</BoatShape>
|
||||
|
||||
<BoatShape ShapeID="5" />
|
||||
|
||||
</BoatShapes>
|
||||
|
||||
<Boats>
|
||||
|
||||
<Boat Type="RC" SourceID="121" ShapeID="0" HullNum="RG01" StoweName="PRO" ShortName="PRO"
|
||||
|
||||
BoatName="Regardless">
|
||||
|
||||
<GPSposition Z="6.840" Y="7.800" X="0.000" />
|
||||
|
||||
<FlagPosition Z="0.000" Y="7.800" X="0.000" />
|
||||
|
||||
</Boat>
|
||||
|
||||
<Boat Type="Mark" SourceID="122" ShapeID="1" HullNum="LC05" StoweName="CON" ShortName="Constellation"
|
||||
|
||||
BoatName="Constellation">
|
||||
|
||||
<GPSposition Z="5.334" Y="3.804" X="0.000" />
|
||||
|
||||
<FlagPosition Z="0.000" Y="3.426" X="0.000" />
|
||||
|
||||
</Boat>
|
||||
|
||||
<Boat Type="Mark" SourceID="123" ShapeID="1" HullNum="LC04" StoweName="MIS" ShortName="Mischief"
|
||||
|
||||
BoatName="Mischief">
|
||||
|
||||
<GPSposition Z="5.334" Y="3.804" X="0.000" />
|
||||
|
||||
<FlagPosition Z="0.000" Y="3.426" X="0.000" />
|
||||
|
||||
</Boat>
|
||||
|
||||
<Boat Type="Mark" SourceID="124" ShapeID="1" HullNum="LC03" ShortName="Atalanta" BoatName="Atalanta">
|
||||
|
||||
<GPSposition Z="5.334" Y="3.804" X="0.000" />
|
||||
|
||||
<FlagPosition Z="0.000" Y="3.426" X="0.000" />
|
||||
|
||||
</Boat>
|
||||
|
||||
<Boat SourceID="125" ShapeID="1" StoweName="VOL" HullNum="LC01" ShortName="Volunteer"
|
||||
|
||||
BoatName="Volunteer">
|
||||
|
||||
<GPSposition Z="5.334" Y="3.804" X="0.000" />
|
||||
|
||||
<FlagPosition Z="0.000" Y="3.426" X="0.000" />
|
||||
|
||||
</Boat>
|
||||
|
||||
<Boat Type="Mark" SourceID="126" ShapeID="1" HullNum="LC13" StoweName="MS2" ShortName="Defender"
|
||||
|
||||
BoatName="Defender">
|
||||
|
||||
<GPSposition Z="5.334" Y="3.804" X="0.000" />
|
||||
|
||||
<FlagPosition Z="0.000" Y="3.426" X="0.000" />
|
||||
|
||||
</Boat>
|
||||
|
||||
<Boat Type="Mark" SourceID="128" ShapeID="1" HullNum="LC01" ShortName="Shamrock" BoatName="Shamrock">
|
||||
|
||||
<GPSposition Z="5.334" Y="3.804" X="0.000" />
|
||||
|
||||
<FlagPosition Z="0.000" Y="3.426" X="0.000" />
|
||||
|
||||
</Boat>
|
||||
|
||||
<Boat Type="Yacht" SourceID="101" ShapeID="4" HullNum="AC4501" StoweName="KOR" ShortName="TEAM KOREA"
|
||||
|
||||
BoatName="TEAM KOREA" Country="KOR">
|
||||
|
||||
<GPSposition Z="1.738" Y="0.625" X="0.001" />
|
||||
|
||||
<MastTop Z="21.496" Y="4.233" X="0.000" />
|
||||
|
||||
</Boat>
|
||||
|
||||
</Boats>
|
||||
|
||||
</BoatConfig>
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Race>
|
||||
|
||||
<RaceID>11080703</RaceID>
|
||||
|
||||
<RaceType>Match</RaceType>
|
||||
|
||||
<CreationTimeDate>2011-08-06T13:25:00-0000</CreationTimeDate >
|
||||
|
||||
<RaceStartTime Time="2011-08-06T13:30:00-0700" Postpone="false" />
|
||||
|
||||
<Participants>
|
||||
|
||||
<Yacht SourceID="101" Entry="Port" />
|
||||
|
||||
<Yacht SourceID="108" Entry="Stbd" />
|
||||
|
||||
</Participants>
|
||||
|
||||
<Course>
|
||||
|
||||
<CompoundMark CompoundMarkID="1" Name="StartLine">
|
||||
|
||||
<Mark SeqID="1" Name="PRO" TargetLat="-36.83" TargetLng="174.83" SourceID="101" />
|
||||
|
||||
<Mark SeqID="2" Name="PIN" TargetLat="-36.84" TargetLng="174.81" SourceID="102" />
|
||||
|
||||
</CompoundMark>
|
||||
|
||||
<CompoundMark CompoundMarkID="2" Name="M1">
|
||||
|
||||
<Mark Name="M1" TargetLat="-36.63566590" TargetLng="174.88543944" SourceID="103" />
|
||||
|
||||
</CompoundMark>
|
||||
|
||||
<CompoundMark CompoundMarkID="3" Name="M2">
|
||||
|
||||
<Mark Name="M2" TargetLat="-36.83" TargetLng="174.80" SourceID="102" />
|
||||
|
||||
</CompoundMark>
|
||||
|
||||
<CompoundMark CompoundMarkID="4" Name="Gate">
|
||||
|
||||
<Mark SeqID="1" Name="G1" TargetLat="-36.63566590" TargetLng="174.97205159" SourceID="104" />
|
||||
|
||||
<Mark SeqID="2" Name="G2" TargetLat="-36.64566590" TargetLng="174.98205159" SourceID="105" />
|
||||
|
||||
</CompoundMark>
|
||||
|
||||
</Course>
|
||||
|
||||
<CompoundMarkSequence>
|
||||
|
||||
<Corner SeqID="1" CompoundMarkID="1" Rounding="SP" ZoneSize="3" />
|
||||
|
||||
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3" />
|
||||
|
||||
<Corner SeqID="3" CompoundMarkID="3" Rounding="Stbd" ZoneSize="6" />
|
||||
|
||||
<Corner SeqID="4" CompoundMarkID="4" Rounding="PS" ZoneSize="6" />
|
||||
|
||||
<Corner SeqID="5" CompoundMarkID="1" Rounding="SP" ZoneSize="3"/>
|
||||
|
||||
</CompoundMarkSequence>
|
||||
|
||||
<CourseLimit>
|
||||
|
||||
<Limit SeqID="1" Lat="-36.8325" Lon="174.8325"/>
|
||||
|
||||
<Limit SeqID="2" Lat="-36.82883" Lon="174.81983"/>
|
||||
|
||||
<Limit SeqID="3" Lat="-36.82067" Lon="174.81983"/>
|
||||
|
||||
<Limit SeqID="4" Lat="-36.811" Lon="174.8265"/>
|
||||
|
||||
<Limit SeqID="5" Lat="-36.81033" Lon="174.83833"/>
|
||||
|
||||
<Limit SeqID="6" Lat="-36.81533" Lon="174.8525"/>
|
||||
|
||||
<Limit SeqID="7" Lat="-36.81533" Lon="174.86733"/>
|
||||
|
||||
<Limit SeqID="8" Lat="-36.81633" Lon="174.88217"/>
|
||||
|
||||
<Limit SeqID="9" Lat="-36.83383" Lon="174.87117"/>
|
||||
|
||||
<Limit SeqID="10" Lat="-36.83417" Lon="174.84767"/>
|
||||
|
||||
</CourseLimit>
|
||||
|
||||
</Race>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RegattaConfig>
|
||||
|
||||
<RegattaID>3</RegattaID>
|
||||
|
||||
<RegattaName>New Zealand Test</RegattaName>
|
||||
|
||||
<CourseName>North Head</CourseName>
|
||||
|
||||
<CentralLatitude>-36.82791529</CentralLatitude>
|
||||
|
||||
<CentralLongitude>174.81218919</CentralLongitude>
|
||||
|
||||
<CentralAltitude>0.00</CentralAltitude>
|
||||
|
||||
<UtcOffset>12</UtcOffset>
|
||||
|
||||
<MagneticVariation>14.1</MagneticVariation>
|
||||
|
||||
</RegattaConfig>
|
||||
Reference in New Issue
Block a user